Onboarding: Google Cloud¶
This guide wires your GCP project into Argmin. Workload Identity Federation is the default; no service account keys are ever generated.
Time required
~15 minutes, plus a single terraform apply.
What this grants Argmin¶
A GCP service account authorized via Workload Identity Federation with four project-scoped read-only roles:
roles/bigquery.dataViewer— read the BigQuery billing-export dataset.roles/monitoring.viewer— Vertex AI monitoring metrics, Cloud Monitoring time series.roles/logging.viewer— Cloud Logging entries (Vertex AI prediction-log inventory).roles/serviceusage.serviceUsageConsumer— list which services your project consumes (no API enablement).
Least-privilege option
If you set billing_dataset_id, the module additionally pins BigQuery access
to that exact dataset — so you can drop the project-level dataViewer later.
The service account has zero write access and no exported keys. The
platform's check_permissions.py enforces this; the bindings are verifiable in
infra/gcp/onboarding/main.tf.
Step 1 — Get the values Argmin will provide¶
Email contact@argmin.co and ask for:
wif_issuer_uri— Argmin's OIDC issuer URL.wif_allowed_subjects— the exact OIDC subject(s) Argmin federates from. Wildcards are rejected by the module.
You will provide back to Argmin:
- The
service_account_emailoutput. - The numeric project number and a friendly project name.
- (Optional) the billing-export dataset ID if you scope down per Step 2.
Step 2 — Configure your terraform.tfvars¶
Create terraform.tfvars in infra/gcp/onboarding/:
project_id = "my-prod-project"
service_account_id = "argmin-readonly" # 6-30 chars, lowercase + hyphens
use_workload_identity = true
wif_pool_id = "argmin-pool" # any unique id within your project
wif_provider_id = "argmin-provider"
wif_issuer_uri = "https://<from Argmin>"
# The OIDC subjects Argmin will sign with. The module rejects wildcards —
# list each explicitly. Ask Argmin for the exact strings.
wif_allowed_subjects = [
"<from Argmin, e.g. system:serviceaccount:argmin:argmin-processor>",
]
# Optional: scope BigQuery viewer to a single dataset instead of project-wide.
# Leave empty to grant project-level dataViewer.
billing_dataset_id = ""
A complete terraform.tfvars.example ships in the module directory.
Step 3 — Apply¶
cd infra/gcp/onboarding
gcloud auth application-default login
gcloud config set project <project_id>
terraform init
terraform plan
terraform apply
Outputs:
service_account_email— copy into your onboarding email.auth_method—workload_identity_federation(neverservice_account_key— the module refuses to create keys).granted_roles— human-readable list of what was granted.
Step 4 — Verify¶
The verify script:
- Confirms the service account exists and has no user-managed keys (
gcloud iam service-accounts keys listreturns only system-managed keys). - Lists IAM bindings at project scope and asserts each is in the read-only allowlist.
- Attempts a write API (e.g.
bigquery.datasets.create) impersonating the SA via WIF and asserts403 Permission denied.
Step 5 — Hand the values to Argmin¶
Reply to your onboarding email with:
service_account_email: <terraform output>
project_id: <project>
project_number: <numeric project number>
wif_pool: projects/<project_number>/locations/global/workloadIdentityPools/argmin-pool
wif_provider: projects/<project_number>/locations/global/workloadIdentityPools/argmin-pool/providers/argmin-provider
billing_dataset: <dataset_id, if scoped>
notes: <anything Argmin should know about your project layout>
Argmin responds within 1 business day confirming federation succeeded and ingestion has started.
Rotating the federation subjects¶
wif_allowed_subjects is a list — rotate without downtime:
- Ask Argmin for the new subject string.
- Add it to the list (don't replace yet) and
terraform apply. - Confirm Argmin is now using the new subject.
- Remove the old subject and
terraform applyagain.
Removing access¶
Deletes the service account, the WIF pool/provider, and all IAM bindings. Notify Argmin first so ingestion can pause cleanly.
Troubleshooting¶
| Symptom | Most likely cause |
|---|---|
| "unauthorized_client" / "subject not allowed" | wif_allowed_subjects is missing the exact subject Argmin signs with. Exact-string, no wildcards. |
| BigQuery query returns empty | billing_dataset_id is set but the dataset doesn't exist or isn't the billing export. Check bq ls. |
| Vertex AI logs missing | Cloud Logging exclusion filters are dropping Vertex AI rows before the sink Argmin reads. |
terraform apply fails creating the WIF pool |
Caller lacks roles/iam.workloadIdentityPoolAdmin. Have an admin grant it, or apply from a CI runner that already has it. |
Reference¶
- Module source:
infra/gcp/onboarding/ - Verify script:
infra/gcp/onboarding/scripts/verify.sh - Trust & security model
- Security policy: https://github.com/argmin-com/.github/blob/main/SECURITY.md