Connects a customer’s Google Cloud project to the AI Orchestrator using Workload Identity Federation (WIF) — the modern, keyless integration pattern used by GitHub Actions, CircleCI, Terraform Cloud, and other SaaS platforms that orchestrate customer infrastructure.
After connecting:
- The orchestrator can deploy resources to your GCP project
- No GCP credentials ever leave your project — there’s no service account JSON key file to manage or rotate
- Trust is scoped to your specific org in the orchestrator via
attribute.org_idbinding; other customers cannot impersonate your service account even if they use the same orchestrator instance
Prerequisites
- A GCP project (active) whose billing account is open — check
with
gcloud billing accounts list: theopencolumn must readTrue. A linked-but-closed account fails every resource create; see GCP project, billing & IAM issues gcloudCLI installed and authenticated to that project- A few minutes — the whole setup is ~5-10 minutes for the first project; subsequent projects are similar
Step-by-step setup
Step 0 — Enable required GCP APIs
The most common cause of “Connect failed with 403” is missing API enablement on the customer project. Run this once per project:
gcloud services enable \
sts.googleapis.com \
iamcredentials.googleapis.com \
cloudresourcemanager.googleapis.com \
compute.googleapis.com \
container.googleapis.com \
storage.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
secretmanager.googleapis.com \
logging.googleapis.com \
monitoring.googleapis.com \
--project=YOUR_PROJECT_IDNew projects need one more grant. On freshly created projects,
Cloud Build runs as the project’s default compute service account —
and Google no longer grants it the storage/build roles legacy projects
had. Without them, every image build dies at submit with a
storage.objects.get 403. Grant once per project:
PROJNUM=$(gcloud projects describe YOUR_PROJECT_ID --format='value(projectNumber)')
for R in roles/storage.objectViewer roles/artifactregistry.writer \
roles/logging.logWriter roles/cloudbuild.builds.builder; do
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:$PROJNUM-compute@developer.gserviceaccount.com" \
--role="$R" --quiet
doneAlso note new-project quota defaults are low (4 external IPs, 32 vCPUs per region) — request increases before heavy use. Details in GCP project, billing & IAM issues.
The first three (sts, iamcredentials, cloudresourcemanager) are
required for WIF authentication itself. The rest are what application
deployments actually use: run/cloudbuild/artifactregistry for
container builds and Cloud Run services, secretmanager for injected
app credentials, and logging/monitoring for the live Logs and
Metrics panels on every deployment. Extend the list for extra
services — e.g. add sqladmin.googleapis.com if deploying Cloud SQL,
cloudkms.googleapis.com for KMS-protected resources.
Step 1 — Create a Workload Identity Pool
gcloud iam workload-identity-pools create orch-pool \
--location=global \
--display-name="AI Orchestrator Pool"Pools are containers for federated identities. One pool per project is typical.
Step 2 — Create an OIDC provider trusting the orchestrator
The provider tells GCP which external identity provider (the orchestrator’s OIDC issuer) to trust, and how to map JWT claims to GCP attributes:
gcloud iam workload-identity-pools providers create-oidc orch-provider \
--location=global \
--workload-identity-pool=orch-pool \
--issuer-uri="https://backend.hivedeploy.in" \
--attribute-mapping="google.subject=assertion.sub,attribute.org_id=assertion.org_id,attribute.cloud_account_id=assertion.cloud_account_id,attribute.environment=assertion.environment"--attribute-mapping value must be one continuous line. Shell soft-wrap or pasting from a document that auto-wraps long lines introduces invisible newlines/spaces that gcloud rejects with a confusing parser error. If you hit that, assign to a variable first and echo "$ATTR_MAPPING" to verify no spaces or newlines before passing it with --attribute-mapping="$ATTR_MAPPING".After creation, get the provider’s full resource path:
gcloud iam workload-identity-pools providers describe orch-provider \
--location=global \
--workload-identity-pool=orch-pool \
--format="value(name)"Output looks like:
projects/123456789012/locations/global/workloadIdentityPools/orch-pool/providers/orch-providerYou’ll paste this into the orchestrator’s connect form.
Step 3 — Create a service account with deployment permissions
gcloud iam service-accounts create orch-deployer \
--display-name="AI Orchestrator Deployer"Grant the SA whatever roles your deployments need. Start narrow — you can always add more later:
PROJECT_ID=$(gcloud config get-value project)
SA_EMAIL="orch-deployer@${PROJECT_ID}.iam.gserviceaccount.com"
# Add roles based on what you'll deploy. These are common starting
# points; trim/expand to fit your actual deployment workloads.
for role in \
roles/container.clusterAdmin \
roles/compute.networkAdmin \
roles/storage.admin \
roles/iam.serviceAccountUser; do
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
--member="serviceAccount:${SA_EMAIL}" \
--role="$role"
doneStep 4 — Grant the orchestrator permission to impersonate this SA
This is the trust grant — it allows JWTs minted by the orchestrator
(with org_id matching your orchestrator org) to impersonate this SA.
First find your orchestrator Org ID — visible at the top of the
GCP connect form in the orchestrator UI, labeled “Your orchestrator
Org ID”. It looks like o-f6bb2d865d8c.
Then:
PROJECT_NUM=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
YOUR_ORG_ID=o-f6bb2d865d8c # from the orchestrator UI
gcloud iam service-accounts add-iam-policy-binding "$SA_EMAIL" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/projects/$PROJECT_NUM/locations/global/workloadIdentityPools/orch-pool/attribute.org_id/$YOUR_ORG_ID"org_id
claim, which doesn’t match this binding, so GCP STS rejects them.Step 5 — Connect via the orchestrator UI
Navigate to Cloud Accounts → Connect cloud → GCP and paste:
| Field | Value |
|---|---|
| Account label | Free-text, e.g. prod-gcp |
| GCP project ID | Your project ID (e.g. your-project-abc123) |
| Workload identity provider | The full path from Step 2 (projects/NNN/locations/.../providers/orch-provider) |
| Service account email | The SA email from Step 3 (orch-deployer@your-project-abc123.iam.gserviceaccount.com) |
| Default region | The GCP region your deployments target (e.g. us-central1) |
Click Connect. The orchestrator runs a smoke test:
- Mints a JWT with
org_idclaim matching your orchestrator org - Exchanges it via
sts.googleapis.comfor a federated token - Impersonates the SA via
iamcredentials.googleapis.com - Reads project metadata as the final check
On success: green “Connected” badge.
Prepare quotas before your first deployment
Connection succeeds against any project — but deployments hit default quotas fast on new projects. The platform checks quota headroom at preflight (you fail in seconds with the exact limit named, not after 20 minutes of churn), but raising limits is a project-owner action only you can take:
| Quota | Typical default | Consumed by |
|---|---|---|
NETWORKS (VPCs) | 5 / project | one per isolated environment |
SSD_TOTAL_GB | 300–500 / region | GKE node pools (a hardened pool can hold 200GB+) |
CPUS | 8–24 / region | multi-VM and multi-zone topologies |
IN_USE_ADDRESSES | 8 / region | load balancers, NAT |
Raise them in Console → IAM & Admin → Quotas before your first production-shaped deployment.
More deployment-time patterns (and which ones the platform self-heals): Troubleshooting GCP deployments.
Troubleshooting
”403 — Service account exists but our principal lacks workloadIdentityUser”
Most common: Step 0 API enablement was skipped. Verify with:
gcloud services list --enabled \
--filter="name:iamcredentials.googleapis.com" \
--project=YOUR_PROJECT_IDIf empty → enable per Step 0.
If APIs are enabled, the next most common cause is that the
workloadIdentityUser binding (Step 4) doesn’t match your
orchestrator’s org_id. Verify the binding contains your actual
org_id (no placeholder like <YOUR_ORG_ID>):
gcloud iam service-accounts get-iam-policy "$SA_EMAIL"Should show:
- members:
- principalSet://iam.googleapis.com/projects/.../attribute.org_id/o-f6bb2d865d8c # ← real ID
role: roles/iam.workloadIdentityUserIf the value after attribute.org_id/ is a placeholder or wrong ID,
re-run Step 4 with the correct value.
”WIF provider doesn’t trust this orchestrator’s issuer”
The OIDC provider’s --issuer-uri (set in Step 2) doesn’t match the
orchestrator’s actual issuer URL. Verify both:
gcloud iam workload-identity-pools providers describe orch-provider \
--location=global --workload-identity-pool=orch-pool \
--format="value(oidc.issuerUri)"Should print https://backend.hivedeploy.in (exactly — no trailing
slash, no path differences). If it shows a different URL, the
provider was created against the wrong issuer. Delete and recreate
the provider with the correct --issuer-uri.
”WIF binding scoped to a different principal”
The federated JWT had a valid signature, but the principal it represents doesn’t match any binding on the SA. Same root cause as the workloadIdentityUser error above — fix per that section.
Probe succeeds but deployments fail with 403 on Compute / Storage / Container
The SA can be impersonated, but it lacks the role to do whatever the deployment is attempting. Either:
- Grant the missing role (Step 3 lists starting roles; add more as needed based on the failure)
- Enable the missing API (
gcloud services enable compute.googleapis.cometc. per Step 0 — extend the list)
The error response body usually names the specific permission missing
(e.g. compute.instances.create); search GCP docs for which role
includes it.
Removing a GCP connection
# 1. Delete the binding from the SA (revokes orchestrator's impersonation)
gcloud iam service-accounts remove-iam-policy-binding "$SA_EMAIL" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/projects/$PROJECT_NUM/locations/global/workloadIdentityPools/orch-pool/attribute.org_id/$YOUR_ORG_ID"
# 2. Remove the cloud-account row from the orchestrator UI
# (Cloud Accounts → click the account → Remove)Optional cleanup (if no other orchestrator integration uses these):
gcloud iam workload-identity-pools providers delete orch-provider \
--location=global --workload-identity-pool=orch-pool
gcloud iam workload-identity-pools delete orch-pool --location=global
gcloud iam service-accounts delete "$SA_EMAIL"How this works under the hood
Every time the orchestrator needs to act on your GCP project:
-
The orchestrator mints a short-lived (5-minute) JWT with claims:
iss:https://backend.hivedeploy.in(orchestrator’s OIDC issuer)aud: full WIF provider resource URLsub:org:<your-org-id>org_id:<your-org-id>(this is whatattribute.org_idmaps from)- plus context like
cloud_account_id,deployment_id,agent_id
-
The JWT is signed with an RSA key whose public part is published at
https://backend.hivedeploy.in/.well-known/jwks.json(your GCP WIF provider fetches and caches this). -
The orchestrator exchanges the JWT at
sts.googleapis.com/v1/tokenfor a federated access token. GCP STS validates the JWT signature, matches the audience to your provider, and projects claims intoattribute.*per your mapping. -
The orchestrator uses the federated token to call
iamcredentials.googleapis.com:generateAccessTokenon your SA. GCP IAM checks if the federated principal hasworkloadIdentityUser— it does (Step 4 binding), scoped to your specificorg_id. -
The resulting GCP access token is cached in the orchestrator’s Redis for ~55 minutes and used for actual GCP API calls during deployments.
The orchestrator holds no long-lived GCP credentials in this design. Compromise of the orchestrator’s RSA signing key (production: stored in GCP KMS HSM) is the only way to impersonate any customer SA — and even then, only customers who set up the trust binding are at risk.
See also
- Connect AWS
- Connect Azure
- Concepts — Security model (per-org isolation deep dive)
- Troubleshooting GCP deployments — post-connect failure patterns