Federating GitLab CI to Azure and GCP With id_tokens
Skip stored cloud keys entirely. Use GitLab id_tokens to federate into Azure workload identity and GCP Workload Identity Federation for short-lived, scoped credentials.
- #gitlab-cicd
- #ai
- #oidc
- #azure
- #gcp
Long-lived cloud service-account keys sitting in CI variables are the credential equivalent of a spare key under the doormat. GitLab’s id_tokens lets you delete them: the runner mints a short-lived JWT, the cloud provider verifies it against GitLab’s OIDC issuer, and the job gets temporary, scoped credentials that expire on their own. AWS gets most of the attention here, but Azure and GCP both federate cleanly too — and the trust-binding details differ enough to be worth walking through.
How id_tokens works in one paragraph
You declare an id_tokens: block in your job. GitLab generates a signed JWT with claims describing the pipeline — project path, ref, whether the ref is protected, the environment. The cloud provider is configured to trust GitLab’s OIDC issuer and to map specific claim values to a specific identity. The job exchanges the JWT for cloud credentials. No secret is ever stored; the trust lives in the cloud-side configuration that says “a token from this GitLab project, on this protected branch, may assume this identity.”
deploy:
id_tokens:
CLOUD_ID_TOKEN:
aud: https://my-cloud-audience
script:
- ./cloud-login.sh # exchanges $CLOUD_ID_TOKEN for creds
The aud (audience) must match what the cloud side expects — it’s the first thing that’s wrong when federation fails.
Federating to GCP Workload Identity Federation
GCP uses a Workload Identity Pool with a provider that points at GitLab’s issuer. You create the pool, add an OIDC provider with GitLab’s issuer URI, and set an attribute mapping plus a condition that pins the GitLab claims.
The job exchanges the token via the gcloud CLI or the credential-configuration file:
deploy-gcp:
id_tokens:
GCP_ID_TOKEN:
aud: https://iam.googleapis.com/projects/PROJECT_NUM/locations/global/workloadIdentityPools/gitlab-pool/providers/gitlab
script:
- echo "$GCP_ID_TOKEN" > token.jwt
- gcloud iam workload-identity-pools create-cred-config "$GCP_ID_TOKEN_AUD"
--service-account="ci@PROJECT.iam.gserviceaccount.com"
--credential-source-file=token.jwt
--output-file=creds.json
- export GOOGLE_APPLICATION_CREDENTIALS=creds.json
- gcloud storage ls # now authenticated
The critical hardening is the provider’s attribute condition. Map project_path and ref_protected from the token and require them, so only your project on a protected branch can impersonate the service account — not every project on gitlab.com that happens to hit the same issuer.
Federating to Azure workload identity
Azure uses federated identity credentials on a managed identity or app registration. You add a federated credential whose issuer is GitLab’s OIDC issuer, whose subject matches a specific GitLab sub claim, and whose audience matches your aud.
deploy-azure:
id_tokens:
AZURE_ID_TOKEN:
aud: api://AzureADTokenExchange
script:
- az login --service-principal
--username "$AZURE_CLIENT_ID"
--tenant "$AZURE_TENANT_ID"
--federated-token "$AZURE_ID_TOKEN"
- az group list # authenticated, no client secret
Azure’s federated credential matches on the subject claim, so you bind it to an exact GitLab subject string — for example one tied to a specific project and protected ref or environment. Because Azure matches a single subject per credential, you typically add one federated credential per environment (staging, production) rather than trying to wildcard.
The pattern that’s identical everywhere
Whatever the cloud, the security model is the same and the dangerous default is the same: binding only on audience is not enough. The audience is shared by everyone on the GitLab issuer. The real control is pinning the GitLab-specific claims — project_path, ref_protected, and ideally environment — on the cloud side, so a fork or an unprotected branch can never trade its token for your credentials. Set the shortest viable credential lifetime, and gate the credential-using job with rules: so it can’t run on fork MR pipelines.
Let AI draft the cloud-side trust — and red-team it
The cloud configuration is where mistakes hide, so I draft it with AI and then specifically ask it to attack its own output:
Prompt: “Generate the GCP Workload Identity Federation provider attribute mapping and condition that lets ONLY GitLab project group/app on a protected branch impersonate the service account ci@… Then act as an attacker: list every way someone could still obtain these credentials given this config, and what claim condition closes each gap.”
The self-attack is what surfaces the real gaps:
Output (excerpt): “Gaps with an audience-only condition: (1) any project on gitlab.com can present a valid token — close by requiring
assertion.project_path == 'group/app'; (2) a feature branch or fork MR can mint a token — close by requiringassertion.ref_protected == 'true'; (3) staging code could reach prod resources — close by also pinningassertion.environment. Recommended condition: …”
Treat that as a draft you must verify against the live config — the model can’t see your actual pool or tenant. Run gcloud/az to confirm the binding, then confirm no static service-account key survives anywhere in your CI variables. For the reusable prompt, see the OIDC keyless cloud auth prompt and the broader GitLab CI/CD category; the AWS-specific variant deserves its own walkthrough.
The bottom line
GitLab id_tokens federates to Azure and GCP just as it does to AWS, and the security win is the same: no stored cloud keys, only short-lived credentials gated by verifiable pipeline claims. GCP binds via a workload-identity-pool provider with an attribute condition; Azure binds via a federated credential matching a specific subject. In both cases the audience alone is worthless as a control — pin project_path, ref_protected, and environment so only your project, on a protected ref, deploying to the named environment, can get in. Draft the cloud-side trust with AI, red-team it, verify against the live config, and delete the old keys.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.