Skip to content

Connect Google Cloud

An Engineer or Admin can configure the Google Cloud connector from the guided setup without a human handoff. No long-lived cloud credentials by default: Venturi’s workload identity reaches the project through Workload Identity Federation, and the module never creates or exports a service-account key. See Docs authority & product state.

Access boundary

The module creates a service account that Venturi impersonates through Workload Identity Federation, with these read roles:

  • roles/bigquery.dataViewer on the billing-export dataset only.
  • roles/monitoring.viewer on the project for Vertex AI and Cloud Monitoring metrics.
  • roles/logging.viewer on the project for Cloud Logging entries. It excludes Data Access audit logs, which require roles/logging.privateLogViewer.
  • roles/serviceusage.serviceUsageConsumer on the project to inspect which APIs, such as Vertex AI, are enabled and their quota state. It cannot enable or disable any API. It also carries serviceusage.services.use, which lets its holder consume quota and billing in the project.

BigQuery access is dataset-scoped from the start: set billing_dataset_id to the billing-export dataset and billing_dataset_only = true, as in the configuration below. If billing_dataset_only is false or billing_dataset_id is empty, the module also grants roles/bigquery.dataViewer on the whole project; do not use that mode.

billing_dataset_id must name a dataset in project_id. The module connects 1 project and grants the dataset-scoped read inside that project, so it cannot grant access to a Cloud Billing export dataset that lives in a separate billing or FinOps project; an apply that names such a dataset fails because the dataset is not found in project_id.

Content-bearing logs. Read access to a log source is not storage of its content. roles/logging.viewer can read Vertex AI container logs, which hold whatever your serving containers write to standard output and standard error, and a project-wide roles/bigquery.dataViewer grant can read the BigQuery table that Vertex AI request-response logging writes, which contains sampled prompts and responses when you enable that logging. The module grants roles/logging.viewer on the project, where it reads the _Required bucket and the _Default view of the _Default bucket, not user-defined log buckets. Scope what that grant reaches by routing Vertex AI container logs to a user-defined log bucket and excluding them from the _Default sink; Vertex AI access logs, which record timestamp and latency for each request, stay in _Default. Keep BigQuery read scoped to the billing-export dataset, and keep request-response logging tables out of that dataset. For any record that still contains content, the collector applies a field allowlist in memory, discards prompt and completion fields before a record is materialized, and never persists, logs, retries, or exports them. The normalized InvocationEvent schema has no field for prompt or completion text.

Steps

1. Generate configuration

Role: Engineer or Admin in Venturi; for the apply, a Google Cloud setup principal that can create the Workload Identity Pool and provider (roles/iam.workloadIdentityPoolAdmin), create the service account and set its IAM policy (roles/iam.serviceAccountAdmin), set project IAM bindings (roles/resourcemanager.projectIamAdmin), and set IAM on the billing-export dataset (for example, roles/bigquery.dataOwner on that dataset). Enabling an API needs serviceusage.services.enable, for example through roles/serviceusage.serviceUsageAdmin.

Workload Identity Federation and service-account impersonation need the IAM, Resource Manager, Service Account Credentials, and Security Token Service APIs in the project. The module does not enable APIs, so enable any that are not already on before the apply:

Bash
gcloud services enable iam.googleapis.com cloudresourcemanager.googleapis.com \
  iamcredentials.googleapis.com sts.googleapis.com --project "<project_id>"

Select Google Cloud in guided setup. The tenant flow generates the exact issuer, allowed subjects, connector ID, and pinned Terraform artifact in-product. Download the pinned Terraform artifact and extract it: the extracted infra/gcp/onboarding/ directory holds the module, terraform.tfvars.example, and scripts/verify.sh. Save the generated values below as infra/gcp/onboarding/terraform.tfvars, run every command on this page from that directory, and keep it, with its Terraform state, for rotation and removal.

Terraform
project_id           = "my-prod-project"
service_account_id   = "venturi-readonly"
wif_pool_id          = "venturi-pool"
wif_provider_id      = "venturi-provider"
wif_issuer_uri       = "<generated in guided setup>"
wif_allowed_subjects = ["<generated exact subject>"]
billing_dataset_id   = "billing_export"
billing_dataset_only = true

Wildcards are rejected. Keep every subject exact.

Leave use_workload_identity out of terraform.tfvars; it defaults to true. Setting it to false skips the pool, provider, and impersonation binding, and the module never creates a service-account key, so the connector has no way to authenticate.

2. Deploy and prove the boundary

Role: the setup principal for the apply; for the local check, a principal that can read the project IAM policy, list the service account’s keys (roles/iam.serviceAccountViewer), and list Workload Identity pools in the project (for example, roles/iam.workloadIdentityPoolViewer), plus roles/iam.serviceAccountTokenCreator on the service account to exercise the write probe. Without the pool-list permission the script prints MISS WIF pool, which fails the check.

Bash
cd infra/gcp/onboarding
export PROJECT_ID="my-prod-project"
gcloud auth login
gcloud auth application-default login
gcloud config set project "$PROJECT_ID"
terraform init
terraform plan
terraform apply
SERVICE_ACCOUNT_EMAIL="$(terraform output -raw service_account_email)" \
  ./scripts/verify.sh

This is the only terraform apply in the setup path; the Deploy step later activates the connector without applying the module again.

Terraform uses the Application Default Credentials from gcloud auth application-default login; verify.sh calls gcloud with the account from gcloud auth login. If a different principal runs the check, sign in as that principal with gcloud auth login before running verify.sh.

The local script confirms the service account has no user-managed keys, prints a role: line for each project-scope role binding, checks the Workload Identity Pool, and attempts a write call, such as BigQuery dataset creation, while impersonating the service account; the write must be denied. The script’s role allowlist is broader than the module: it prints roles/bigquery.dataViewer, roles/iam.serviceAccountTokenCreator, and roles/iam.workloadIdentityUser as OK at project scope, so a run with no SEC line does not by itself prove that no write-capable role is bound. Read the role lines instead: they must be exactly role: roles/monitoring.viewer, role: roles/logging.viewer, and role: roles/serviceusage.serviceUsageConsumer, and any other role: line is a security finding. Without roles/iam.serviceAccountTokenCreator, the script reports the write probe as SKIP, which does not fail the check; automated credential validation runs the denied-write probes as Venturi’s identity. To exercise the probe locally, grant the role for the check and remove it afterward. Connector activation performs the positive BigQuery, Logging, and Monitoring reads through federation. See Verify & confirm.

3. Register outputs and validate

Enter the service-account email, project number, Workload Identity Pool provider resource name (projects/<project_number>/locations/global/workloadIdentityPools/venturi-pool/providers/venturi-provider), and billing dataset in the connector step. Automated credential validation checks the issuer, exact subject, federation exchange, positive reads, and write denial.

4. Inspect evidence

Open the readiness result and /invocations. Review coverage, unknown ownership or billing dimensions, and source freshness.

Success evidence

  • terraform apply succeeds with no service-account key resource.
  • verify.sh exits 0 with no SEC or MISS line, its project-scope role lines are exactly role: roles/monitoring.viewer, role: roles/logging.viewer, and role: roles/serviceusage.serviceUsageConsumer (any other role: line, including roles/bigquery.dataViewer, roles/iam.serviceAccountTokenCreator, or roles/iam.workloadIdentityUser, is a security finding), a write-probe SKIP does not fail it, and the connector’s positive read probes pass.
  • Automated credential validation shows the exact issuer and subject accepted.
  • The 1st Google Cloud-backed AttributionRecord appears in /invocations.

Recovery

Failure Action
unauthorized_client or subject rejection Compare the exact generated issuer and subject; remove wildcard or whitespace drift and reapply.
terraform apply fails with a permission error on the pool, service account, or an IAM binding Grant the setup principal the matching role from step 1, then apply again.
terraform apply or validation fails with SERVICE_DISABLED or “API has not been used in project” Enable the named API with gcloud services enable as shown in step 1, wait a few minutes for it to take effect, then apply or validate again.
terraform apply fails with Not found: Dataset for the billing dataset billing_dataset_id names a dataset outside project_id, or a dataset that does not exist. Set it to the billing-export dataset in project_id; the module cannot grant access to a dataset in another project.
verify.sh prints a role: line other than roles/monitoring.viewer, roles/logging.viewer, and roles/serviceusage.serviceUsageConsumer Security finding, even when the script prints it as OK. Disable the connector, remove the extra project-scope binding, apply, and rerun verify.sh.
verify.sh prints MISS WIF pool although the pool exists The identity running the script cannot list Workload Identity pools. Grant it roles/iam.workloadIdentityPoolViewer on the project, or run the check as the setup principal, then rerun.
verify.sh prints role: roles/bigquery.dataViewer The project-wide BigQuery grant is present. Set billing_dataset_id and billing_dataset_only = true, apply, and rerun verify.sh.
Billing query is empty Confirm the export dataset, project, location, and dataset-scoped binding.
Vertex evidence is missing Inspect Logging exclusions and confirm the expected metadata log exists.
Positive read is denied Add only the named missing read role at the narrowest scope, then rerun validation.
verify.sh reports the write probe as SKIP Not a failure. To exercise the write probe, grant the person running the script roles/iam.serviceAccountTokenCreator on the service account, rerun, then remove the grant.
Freshness becomes stale Check the latest billing-export partition and readiness probe timestamp.

Support is an optional escalation path after the validation evidence is available.

Rotate or revoke

wif_allowed_subjects is a list, so both subjects are accepted during rotation. Review the subject at least every 12 months:

  1. In Integrations / Google Cloud, generate the next exact federation subject.
  2. Add it to wif_allowed_subjects, keeping the current subject, and apply.
  3. Activate the new subject in the connector settings and rerun automated credential validation.
  4. Remove the previous subject, apply again, and rerun verify.sh.

Do not use wildcards to bridge rotation.

To revoke access, disable the connector in Integrations / Google Cloud, then run:

Bash
cd infra/gcp/onboarding
terraform destroy

Confirm the service account, pool, provider, and bindings are absent and record the revocation result in the connector audit record.

Reference

Give feedback on this page

Sign in to send feedback. Opens in a new tab.

Copy page details
Docs feedback: Connect Google Cloud
Page: https://docs.venturi.systems/onboarding/gcp/