Skip to main content

Connecting your GCP project(s)

This is the complete, do-it-once setup to let the platform scan your Google Cloud for misconfigurations and compliance gaps. It is agentless and read-only: you never give us a human password or console login — you create a read-only service account in your own project, grant it Viewer + Security Reviewer, and hand us its key. By IAM, that identity can read every resource's configuration and security posture, change nothing, and read none of your data.

Unlike AWS — where you create a role we assume cross-account and we store no secret at all — Google Cloud needs an actual credential: a service-account key (JSON). You paste it into the console once. On our side it is write-only: stored encrypted in AWS Secrets Manager under a dedicated KMS key, readable only by an isolated credential broker (a Lambda) that, for each scan, mints a short-lived (~1 hour) read-only access token. The durable key never reaches a scanner or worker, is never returned by any API, and is never shown again after you paste it.

:::tip Genuinely one-and-done A GCP service-account key does not carry a forced expiry (unlike Azure's client secret, which you must rotate). Connect once and it keeps working — no calendar reminder, no re-paste. :::

You have two paths:

Both end the same way: paste the key back, validate access, then run your first scan.

:::info What we can and cannot see The service account holds only Viewer (roles/viewer) and Security Reviewer (roles/iam.securityReviewer). That is configuration and security posture — resource settings, IAM policies, metadata. No write access. No reading your data (no object contents from Cloud Storage, no database rows) — only how things are configured. Nothing beyond those two roles is granted. :::


Before you start

From the platform (your console → CloudConnect GCP account), click Add account. This time there's nothing to copy out first — GCP is credential- based, so the flow is: you create the read-only service account below, then paste its key JSON back in.

ValueWhat it is
Service-account key (JSON)The credential the service account authenticates with. You create it below and paste it into the console once. We store it write-only (encrypted, broker-only); it is never shown again.
Project id (optional)A label / scope hint you can attach as account_id. Optional — scope is actually controlled by where you granted the two roles (one project vs. a folder/org), not by this field.

Behind the scenes this is the API call POST /org/gcp/accounts (your UI does it for you); the account is created in state pending until you paste the key and validate.


Create the read-only service account

The goal of both paths is identical: one service account named set-cspm-scanner, granted roles/viewer + roles/iam.securityReviewer, plus a key to hand us.

Path A — Terraform

Our onboarding template is main.tf. It creates the service account, grants the two read-only roles, and outputs the key JSON. The platform links you a copy, or copy it here:

main.tf
terraform { required_providers { google = { source = "hashicorp/google", version = "~> 5.0" } } }
variable "project_id" { type = string }
provider "google" { project = var.project_id }
resource "google_service_account" "set_scanner" {
account_id = "set-cspm-scanner"; display_name = "S.E.T system (read-only CSPM)"; project = var.project_id
}
resource "google_project_iam_member" "viewer" {
project = var.project_id; role = "roles/viewer"; member = "serviceAccount:${google_service_account.set_scanner.email}"
}
resource "google_project_iam_member" "security_reviewer" {
project = var.project_id; role = "roles/iam.securityReviewer"; member = "serviceAccount:${google_service_account.set_scanner.email}"
}
resource "google_service_account_key" "set_scanner" { service_account_id = google_service_account.set_scanner.name }
output "service_account_key_json" { value = base64decode(google_service_account_key.set_scanner.private_key); sensitive = true }

Deploy it (single project):

terraform init
terraform apply -var project_id=YOUR_PROJECT_ID

# then read the key JSON back out (it's marked sensitive, so ask for it explicitly):
terraform output -raw service_account_key_json

Copy that JSON — you'll paste it into the console in the next step.

:::note Many projects? Grant the roles higher up. The template above grants the two roles at the project level. To scan every project with a single service account, grant them at the folder or organization level instead — swap the two google_project_iam_member resources for google_folder_iam_member (with a folder id) or google_organization_iam_member (with an org_id). One service account, one key, and the scan covers every project beneath that folder/org. :::

Path B — gcloud CLI

The same three actions by hand, in the project you want scanned:

# 1. create the read-only service account
gcloud iam service-accounts create set-cspm-scanner \
--display-name="S.E.T system (read-only CSPM)"

# 2. grant the two read-only roles
gcloud projects add-iam-policy-binding PROJECT \
--member="serviceAccount:set-cspm-scanner@PROJECT.iam.gserviceaccount.com" \
--role="roles/viewer"

gcloud projects add-iam-policy-binding PROJECT \
--member="serviceAccount:set-cspm-scanner@PROJECT.iam.gserviceaccount.com" \
--role="roles/iam.securityReviewer"

# 3. create and download the key
gcloud iam service-accounts keys create key.json \
--iam-account=set-cspm-scanner@PROJECT.iam.gserviceaccount.com

key.json is the credential you'll paste back. (For multi-project coverage, use gcloud resource-manager folders add-iam-policy-binding / gcloud organizations add-iam-policy-binding with the same two roles instead of the project bindings.)


Paste the key back

In the platform, open the account you just added and paste the service-account key JSON into the field, optionally setting a project id as account_id, then save. That's the whole connection.

Behind the scenes:

POST /org/gcp/accounts
{
"provider": "gcp",
"account_id": "<project id or label>",
"gcp_service_account_key": { ...the key JSON... }
}

Remember the key is write-only from here on — it goes straight to encrypted storage and is never returned or displayed again. Project scoping is optional: the scan covers every project the service account's roles can see, which is decided by where you granted the roles (one project, or a whole folder/org).

Now validate.


Validate access

Before any scan, confirm the key works. In the platform click Validate on the account (API: POST /org/gcp/accounts/{id}/validate). This triggers a live token mint through the credential broker — we exercise the real path a scan uses — and report back:

  • validated ✓ — the broker minted a short-lived token; the account is ready to scan.
  • invalid ✗ — with the reason (bad or rotated/deleted key, or the two roles aren't granted). Fix and re-validate.

Check overall readiness any time with the status endpoint (GET /org/gcp/status{ enabled, validated_accounts, can_run }).


Run your first scan

Once at least one account is validated:

  • Platform: Cloud → Run scan.
  • API: POST /org/scans { "module": "gcp" }.

The scan runs one read-only pass and returns when done. It is gated on a validated account (you'll get a 409 if none is validated yet), and the normal one-scan-per-14-days cooldown applies (independent of AWS/Azure and of EASM/DAST).

When it finishes you'll have:

  • Findings — the failures, grouped by issue with the affected resources listed and a "5 of 20 remaining" rollup.
  • Full posture — every pass and fail (GET /org/gcp/results), filterable by service, severity, project.
  • Compliance — pick any framework (GET /org/gcp/frameworks lists them) and get an overall score plus a control-by-control breakdown (GET /org/gcp/compliance?framework=CIS-GCP-2.0 → e.g. "overall score + per- control breakdown"). One scan reports against every framework — CIS GCP, ISO 27001, SOC 2, NIST, PCI, and more. The framework is a view, never a re-scan.

Fix, then prove it's fixed

Cloud findings use the same lifecycle as the rest of the platform, tracked per resource:

  1. Mark a finding In Progress / Resolved / Accepted Risk / False Positive.
  2. Fix it in GCP.
  3. Rescan. Resolution is confirmed by the scan, not by the click: a finding you marked Resolved closes when the next scan no longer sees it; a fix you didn't triage auto-closes after 2 consecutive clean scans. If a closed issue comes back it reopens (regression). Fix 15 of 20 affected resources and exactly those 15 close — the other 5 stay open.

A finding that keeps showing up across scans is flagged recurring so you can spot what isn't sticking.


Troubleshooting

SymptomCause / fix
Validate returns invalid (auth failed)The key was rotated or deleted in GCP. Create a fresh key (gcloud iam service-accounts keys create … or terraform apply) and paste the new JSON back.
Validate returns invalid: missing rolesThe service account isn't granted both roles/viewer and roles/iam.securityReviewer. Re-grant both (project, or folder/org for multi-project) and re-validate.
Scan sees fewer projects than expectedThe roles were granted at the project level. To cover more, grant them at the folder or organization level so the one service account sees every project beneath it.
Wrong project in scopeThe account_id/project id is only a label — scope follows where the roles were granted. Adjust the role bindings, not the field.
"Can you see our data?"No. Viewer + Security Reviewer only — configuration and security posture. No write access, no object/database contents.

What we never expose

The scanning engine is white-labeled end to end. It isn't named in your findings (engine name and links are scrubbed), and it isn't visible in your GCP audit logs: activity is attributed to your own service account by its name (set-cspm-scanner), not to any underlying tool. On findings, the evidence source reads simply cloud_cspm. You see Binary Networks Scanner and your own service account — nothing else.