Skip to content

Google Cloud

Connecting from the web app?

Follow the prerequisites and credential creation instructions below, then return to Cloud Security → Settings → Providers → Add provider. Enter the provider IDs under Configuration and save the credential using New secret under Permissions. Run Test Provider, fix required failures, and save. The LimaCharlie CLI examples below are an alternative. First-time setup and verification explains the full journey.

Collects the Google Cloud estate across every project in scope — compute, serverless (Cloud Run and Cloud Functions), storage, networking, IAM, KMS, databases, secrets, Pub/Sub — plus CIEM (who can reach what), Vertex AI inventory, and agentless workload vulnerabilities from VM Manager.

Auth model: a service-account key (JSON) granted read-only roles at the organization, folder, or project you want enumerated. The collector discovers every active project underneath that node by itself.

Prerequisites

For a first connection, choose one project containing resources you recognize. Find its project ID in the Google Cloud project selector; the display name and numeric project number are different values. In the LimaCharlie wizard, enter that ID in Project and leave the broader scope field empty.

A service account is an identity for the collector, separate from your personal Google login. Its key proves its identity; IAM roles decide what it may read.

  1. A GCP project to own the service account (any project you control — it does not have to be one being scanned).
  2. Permission to grant IAM roles at the scope you intend to connect (Organization Admin / Folder Admin / Project IAM Admin).
  3. Permission to enable APIs in the service account's project, or an administrator who can complete the following step.

Enable the APIs

Enable these APIs in the service account's own project. Both tabs use the same list; you only need to follow one method.

  1. Select the service account's project in Google Cloud.
  2. Open APIs & Services → Library, search for a service below, and select Enable. Repeat for the full list; leave already enabled APIs on.
  3. Check Enabled APIs & services in that project to confirm the list.

You need permission to enable services. If Enable is unavailable, ask your Google Cloud administrator. Google's API enablement guide explains this console workflow.

Open Cloud Shell in Google Cloud, or use an installed and authenticated Google Cloud CLI. Set the project that owns the service account:

SA_PROJECT="your-service-account-project-id"
gcloud services enable \
  cloudresourcemanager.googleapis.com \
  serviceusage.googleapis.com \
  iam.googleapis.com \
  compute.googleapis.com \
  storage.googleapis.com \
  secretmanager.googleapis.com \
  cloudkms.googleapis.com \
  bigquery.googleapis.com \
  sqladmin.googleapis.com \
  pubsub.googleapis.com \
  apikeys.googleapis.com \
  osconfig.googleapis.com \
  containeranalysis.googleapis.com \
  run.googleapis.com \
  cloudfunctions.googleapis.com \
  aiplatform.googleapis.com \
  notebooks.googleapis.com \
  recommender.googleapis.com \
  policyanalyzer.googleapis.com \
  cloudidentity.googleapis.com \
  --project "$SA_PROJECT"
API Library name Service ID
Cloud Resource Manager API cloudresourcemanager.googleapis.com
Service Usage API serviceusage.googleapis.com
Identity and Access Management (IAM) API iam.googleapis.com
Compute Engine API compute.googleapis.com
Cloud Storage JSON API storage.googleapis.com
Secret Manager API secretmanager.googleapis.com
Cloud Key Management Service (KMS) API cloudkms.googleapis.com
BigQuery API bigquery.googleapis.com
Cloud SQL Admin API sqladmin.googleapis.com
Cloud Pub/Sub API pubsub.googleapis.com
API Keys API apikeys.googleapis.com
OS Config API osconfig.googleapis.com
Container Analysis API containeranalysis.googleapis.com
Cloud Run Admin API run.googleapis.com
Cloud Functions API cloudfunctions.googleapis.com
Vertex AI API aiplatform.googleapis.com
Notebooks API notebooks.googleapis.com
Recommender API recommender.googleapis.com
Policy Analyzer API policyanalyzer.googleapis.com
Cloud Identity API cloudidentity.googleapis.com

APIs must also be on in the projects being scanned

A scanned project with a service API disabled is skipped for that service — treated as covered, empty, never as a permission failure. That is usually what you want. provider test reports a disabled API as a passing check with an explanatory note, precisely so you do not mistake it for a missing grant.

Only some of these surfaces have a preflight check

The preflight probes the surfaces listed in the check table below. The rest — KMS, BigQuery, Cloud SQL, Pub/Sub, API keys, Workbench notebooks — are exercised only during the sweep. If one of their APIs is disabled, that inventory type simply comes back empty while the provider test stays green, so enable the full list above rather than trimming it to what the test covers.

Required roles

Grant at the scope node (organization, folder, or project). Roles are inherited down the hierarchy, so an org-level grant covers every project.

Role Why Preflight check
roles/viewer The read surface for every resource type (compute, storage, networking, databases, Pub/Sub, KMS, …) compute, storage, projects
roles/iam.securityReviewer *.getIamPolicy across services — the CIEM graph (who can access what) iam

Prefer a tighter grant?

roles/viewer is the simple, well-understood baseline. A least-privilege alternative is roles/browser (hierarchy traversal) plus the per-service viewer roles you care about, still with roles/iam.securityReviewer. Use provider test to confirm the result — it names every surface that is still denied.

If you use Code Security to scan container images, add roles/artifactregistry.reader to that list (see Container image scanning). roles/viewer already includes it; the tighter set does not.

Optional roles

Each adds one inventory or analysis surface. Skipping one leaves that surface unobserved; the sweep still succeeds.

Role Unlocks Preflight check
roles/secretmanager.viewer Secret metadata inventory (names/rotation posture — never secret values) secret_manager
roles/osconfig.vulnerabilityReportViewer Agentless workload vulnerabilities from VM Manager osconfig_vuln
roles/osconfig.inventoryViewer The OS-inventory join that attaches package name + installed/fixed version to each CVE (not probed — exercised during the sweep)
roles/containeranalysis.occurrences.viewer Container image vulnerabilities from Artifact Analysis, for images in Artifact Registry and Container Registry artifact_analysis
roles/artifactregistry.reader Code Security pulling your private container images to scan them. Already included in roles/viewer; add it if you use the tighter set of roles (not probed — exercised when an image is scanned)
roles/recommender.iamViewer Unused-privilege findings (activity-based CIEM) activity_ciem
roles/policyanalyzer.activityAnalysisViewer Dormant-identity / last-authentication findings activity_ciem
roles/aiplatform.viewer Vertex AI endpoint and model inventory vertex_ai
roles/run.viewer Cloud Run service inventory and its public-access verdict (run.services.list + run.services.getIamPolicy) serverless
roles/cloudfunctions.viewer Cloud Functions inventory (1st and 2nd gen) plus their invoker policies (cloudfunctions.functions.list + cloudfunctions.functions.getIamPolicy) serverless
roles/cloudidentity.groups.readonly Google-group membership expansion, so group: IAM bindings resolve to real people cloud_identity

What container image scanning gives you, and what it does not

With roles/containeranalysis.occurrences.viewer granted and Artifact Analysis enabled in the project, each vulnerable image is reported against its digest, so one image is one finding subject however many tags point at it — the same shape we use for Amazon ECR and Azure Container Registry, so an image is one thing to triage across clouds.

Three limits are worth knowing up front:

  • Images are not inventoried yet. A vulnerable image appears as a finding subject, not in Inventory or the topology, and nothing links it to the workloads that run it.
  • An enabled verdict is about the API, not every repository. We read whether Artifact Analysis answers for the project. That does not prove on-push scanning is configured for every repository.
  • Very large registries are skipped whole, not truncated. A project whose registries hold more scan results than our per-project ingestion budget reports none of them rather than an arbitrary subset — a truncated set would look like a shrinking estate. A busy CI project that keeps every historical build image is the case that hits this. The results are not lost on Google's side; we simply do not ingest them yet.

Serverless already works on the required baseline

The required roles/viewer + roles/iam.securityReviewer pair already grants both the list and the getIamPolicy reads for Cloud Run and Cloud Functions, so you do not need to add anything for serverless coverage. The two roles above exist for the least-privilege alternative (roles/browser plus per-service viewers), where they are what turns serverless coverage on.

Both halves of each grant matter, and the second is the one that gets missed: without getIamPolicy we can list a service but cannot tell whether it is invocable by anyone on the internet. In that case we report no verdict rather than guess — so serverless exposure findings are absent, not empty, which is a different thing from "you have none".

Services published only through a load balancer

A Cloud Run service or function whose ingress is internal and Cloud Load Balancing cannot be reached at its own run.app URL, but it can be published to the internet through an external load balancer in front of it. We do not yet collect load balancers, so such a service is inventoried but is not reported as internet-facing. Services reachable directly at their own URL are assessed normally.

2nd-gen functions are authorized as Cloud Run services

A 2nd-gen Cloud Function runs on Cloud Run, and its invoker permission lives on the underlying Cloud Run service (roles/run.invoker) rather than on the function (roles/cloudfunctions.invoker is the 1st-gen role). So assessing a 2nd-gen function's public access reads the Cloud Run side, not the Cloud Functions side.

If you are assembling a least-privilege grant rather than using the required baseline, grant both roles/run.viewer and roles/cloudfunctions.viewer and let provider test confirm it: the serverless check exercises both APIs and reports each separately, so it will tell you if one half is missing rather than leaving you to reason about role contents.

osconfig_vuln does not prove the inventory join

The osconfig_vuln check probes the vulnerability-report read only, so it passes with roles/osconfig.vulnerabilityReportViewer alone. If roles/osconfig.inventoryViewer is missing, the sweep still records the CVEs but skips the OS-inventory join and moves on — the symptom is vulnerability rows with no package name and no fixed version, not a failing check.

Workbench notebooks are a separate API

Vertex AI Workbench notebook inventory comes from the Notebooks API (notebooks.googleapis.com), not from the Vertex AI API, and it is not covered by the vertex_ai check. Enable that API too if you want notebooks inventoried.

Recommender needs only the list permission

Google's own walkthrough for reviewing role recommendations in the console also asks for roles/iam.roleViewer and a resource IAM-admin role. Those cover applying recommendations interactively; this connector only lists them, and the roles/viewer baseline already covers the role-metadata reads.

Cloud Identity groups are granted elsewhere

roles/cloudidentity.groups.readonly (or the Groups Reader role) is granted at the Cloud Identity account/customer level in the Google Admin console, not on a GCP project. Without it, IAM bindings to groups remain visible but their membership is not expanded, so "which humans can reach this bucket" stops at the group.

Container image scanning by Code Security

Code Security scans the container images your repositories and workloads reference by digest. To scan a private image in Artifact Registry (*-docker.pkg.dev) or gcr.io, it pulls the image using this connection's service account. That service account needs roles/artifactregistry.reader on the project that hosts the image. That is often not the project where the image runs. gcr.io is served by Artifact Registry, so the same role covers it.

  • With roles/viewer at the organization or folder, you already have it.
  • With the tighter set of roles, grant it at the same node (variables as in Create the service account):

    gcloud organizations add-iam-policy-binding "$ORG_ID" \
      --member "serviceAccount:${SA}" \
      --role roles/artifactregistry.reader
    
  • Images kept in a separate project, such as a shared build or artifact project, need the grant there too if that project is outside the connected scope.

  • A project still on legacy Container Registry serves gcr.io images from Cloud Storage. There the service account needs roles/storage.objectViewer on the project's artifacts.<project>.appspot.com bucket instead.

Without the role, the image is not scanned and its status reads registry_permission_denied, naming the registry and this role. The code security status shows image_registry_permission. A refused image is retried less and less often, down to once a day. It keeps being retried, so granting the role fixes it without any other change. To retry right away, use Sync now on the source-control connection (for example GitHub) whose scans reference the image.

Create the service account

Choose the same scope in the provider configuration and in the role grants. A project grant covers one project; a folder or organization grant covers its projects. The web-console steps support each scope. The retained CLI example below uses an organization and names the command substitutions for narrower scopes.

  1. Select the project that will own the credential. Open IAM & Admin → Service Accounts → Create service account and create lc-cloudsec.
  2. Copy the service account's email address. Select the project, folder, or organization you want to scan, then open IAM & Admin → IAM → Grant access. Use that email as the principal and grant Viewer (roles/viewer) and Security Reviewer (roles/iam.securityReviewer), as listed above. Add optional roles only for the data you want to collect.
  3. Return to the service account's project, open the account, then Keys → Add key → Create new key → JSON. Download the key. If key creation is blocked by organization policy, ask your Google Cloud administrator to resolve it.
  4. In the wizard's Permissions step, select New secret, give it a name, and paste the complete downloaded JSON. Do not add another secret wrapper.
  5. Run Test Provider. Fix required failures and check which optional data is unavailable. Save and verify a known resource in Inventory.

See Google's service account key instructions for the console workflow. Complete the API prerequisites above as well as the role grants; a key alone does not enable collection.

Open Cloud Shell, or use an installed and authenticated gcloud CLI.

The following example grants access to an organization. Replace ORG_ID and SA_PROJECT with your values; do not use this wider scope for a one-project pilot unless you intend to grant organization-wide access.

SA_PROJECT=my-security-project
ORG_ID=123456789                     # organization ID, not project ID

gcloud iam service-accounts create lc-cloudsec \
  --display-name "LimaCharlie Cloud Security" \
  --project "$SA_PROJECT"

SA="lc-cloudsec@${SA_PROJECT}.iam.gserviceaccount.com"

# Required
for ROLE in roles/viewer roles/iam.securityReviewer; do
  gcloud organizations add-iam-policy-binding "$ORG_ID" \
    --member "serviceAccount:${SA}" --role "$ROLE"
done

# Optional surfaces. roles/viewer above already lets Code Security pull private
# container images; if you replace it with a tighter set, add
# roles/artifactregistry.reader here.
for ROLE in roles/secretmanager.viewer \
            roles/osconfig.vulnerabilityReportViewer \
            roles/osconfig.inventoryViewer \
            roles/recommender.iamViewer \
            roles/policyanalyzer.activityAnalysisViewer \
            roles/aiplatform.viewer \
            roles/containeranalysis.occurrences.viewer \
            roles/run.viewer \
            roles/cloudfunctions.viewer; do
  gcloud organizations add-iam-policy-binding "$ORG_ID" \
    --member "serviceAccount:${SA}" --role "$ROLE"
done

gcloud iam service-accounts keys create sa-key.json \
  --iam-account "$SA" --project "$SA_PROJECT"

For a folder scope use gcloud resource-manager folders add-iam-policy-binding <FOLDER_ID>; for a single project use gcloud projects add-iam-policy-binding <PROJECT_ID>.

Create the credentials secret

The secret value is the service-account key JSON itself — no wrapper.

In LimaCharlie, open Organization Settings → Secrets Manager → Add. Name the secret gcp-collector-sa and paste the complete downloaded key JSON into its value. Save it enabled. Do not paste the example JSON from a guide or add an outer secret property.

python3 -c 'import json,sys;print(json.dumps({"secret":open("sa-key.json").read()}))' \
  > gcp-secret.json

limacharlie hive set --hive-name secret --key gcp-collector-sa \
    --input-file gcp-secret.json --enabled

Create the provider record

provider.yaml:

provider_type: gcp
gcp_scope: organizations/123456789      # or folders/456 or projects/my-project
credentials: hive://secret/gcp-collector-sa
internal_domains: [example.com]
refresh: 6h
Field Meaning
gcp_scope The node to enumerate: organizations/{id}, folders/{id}, or projects/{id}. Every active project underneath is swept.
gcp_project Alternative to gcp_scope for a single project. Supply one or the other.

In the web app: Add provider → GCP, then set the scope, Credentials, and the Sync cadence (pick a preset, or Custom interval for a duration of your own).

Verify

limacharlie cloudsec provider test --input-file provider.yaml

The report opens with the config and credential checks common to every provider, documented once in Provider Setup; the GCP-specific checks follow.

Check Required Meaning if it fails
auth The key could not mint a token, or the scope node is unreachable. Nothing else can be probed.
projects (folder/org scope only) resourcemanager.projects.list denied — no project can be discovered under the scope. A single-project scope has nothing to enumerate, so this check is not reported at all.
compute compute.instances.list denied — no compute inventory.
storage storage.buckets.list denied — no storage inventory.
iam getIamPolicy and/or serviceAccounts.list denied — the CIEM access graph cannot be built.
secret_manager Secret-store inventory unavailable.
activity_ciem Unused-privilege and dormant-identity findings unavailable.
osconfig_vuln Workload vulnerability findings unavailable.
vertex_ai Vertex AI endpoint inventory unavailable.
serverless Cloud Run / Cloud Functions inventory unavailable, and with it the "invocable by anyone on the internet" verdict for that tier. Reported per API, so a partial grant names the half that is missing.
cloud_identity Group membership is not expanded; group: bindings do not resolve to people.

Org-scope tests probe one representative project

For a folder/organization scope the preflight picks the first active project under the node and probes there — IAM grants are inherited, so one project answers "is this granted". If that project happens to have a service API disabled, the check passes with a note saying the grant was neither proven nor disproven.

Troubleshooting

provider test result Cause Fix
auth fails: PERMISSION_DENIED on the scope The service account has no binding at that org/folder/project Grant roles/viewer at the scope node (not just on the SA's own project)
auth fails: "Cloud Resource Manager API has not been used in project <number>" on an organization or folder scope An org/folder has no project of its own, so the API-enablement check is billed to the caller's project — <number> is the service account's project, not a project being scanned. The console only offers to enable APIs per project, which makes this look unresolvable at the org level gcloud services enable cloudresourcemanager.googleapis.com --project "$SA_PROJECT" (see Prerequisites)
projects fails Missing resourcemanager.projects.list roles/viewer or roles/browser at the scope node
iam fails on getIamPolicy roles/viewer alone does not cover every getIamPolicy Add roles/iam.securityReviewer
A check passes with "API not enabled on the probed project" Benign — the sweep skips API-disabled projects Enable the named API if you want that surface; otherwise ignore
activity_ciem fails with Recommender API not enabled Recommender / Policy Analyzer not enabled on the probed project Enable recommender.googleapis.com and policyanalyzer.googleapis.com
serverless fails on run only The grant reaches Cloud Functions but not Cloud Run Add roles/run.viewer. 2nd-gen functions are authorized as Cloud Run services, so without that read they list with no public-access verdict
Cloud Run services appear but none is ever flagged public getIamPolicy is denied on Cloud Run, so the invoker verdict is unobserved rather than negative Add roles/iam.securityReviewer (or roles/run.viewer) and re-run the sweep
Inventory is missing whole projects Those projects are not ACTIVE, or the grant is on a narrower node Confirm project state, and that the binding is at the scope you configured