Git, CI/CD & GitOpsXLIII · OIDC and Short-Lived CredentialsAzureGCP
OIDC in Azure and GCP — Workload Identity Federation; the federation pool
What you'll learn
- Configure Azure Workload Identity Federation for GitHub Actions using actions/azure/login@v2
- Configure GCP Workload Identity Federation for GitHub Actions using google-github-actions/auth@v2
- Recognise the difference between the AWS role model and the Azure/GCP federation pool model
- Map the trust policy subject claims to repo + branch + workflow path in both clouds
Prerequisites
Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x
Azure and GCP implement OIDC federation differently from AWS but converge on the same outcome: a per-job token issued by the forge is exchanged for a short-lived cloud credential scoped to the workflow. Azure uses Workload Identity Federation with a federated credential on an Entra ID app registration; GCP uses Workload Identity Federation with a workload identity pool and provider. The trust relationship model differs; the short-lived credential outcome is identical.
Azure Workload Identity Federation
Azure Workload Identity Federation lets a GitHub Actions workflow exchange an OIDC token for an Azure access token without a service principal secret. The configuration has three pieces:
flowchart LR
APP["Entra ID\napp registration"] --> FED["Federated credential\n(issuer + subject)"]
FED --> POOL["Azure accepts\nOIDC tokens from GitHub"]
POOL --> J["actions/azure/login@v2\nexchanges JWT for Azure token"]
J --> AT["Azure access token\n(~1 hour)"]
- App registration. An Entra ID (Azure AD) application that represents the GitHub Actions workflow. The app has a service principal with the Azure permissions the workflow needs.
- Federated credential. A credential on the app registration that
trusts the GitHub Actions OIDC issuer. The federated credential
specifies the issuer URL and a subject pattern (for example,
repo:acme/infra:ref:refs/heads/main). actions/azure/login@v2. The GitHub Actions action that fetches the OIDC token and exchanges it for an Azure access token.
The federated credential is configured via the Azure portal or the Azure CLI:
az ad app federated-credential create \
--id "$APP_ID" \
--parameters credential.json
The credential.json file specifies the issuer, subject, and audience:
{
"name": "github-actions-deploy",
"issuer": "https://token.actions.githubusercontent.com",
"subject": "repo:acme/infra:ref:refs/heads/main",
"audience": "api://AzureADTokenExchange"
}
The subject matches the sub claim in the OIDC token; the
audience matches the aud claim (api://AzureADTokenExchange is
the standard Azure audience for workload identity federation).
The Azure workflow
A workflow that uses OIDC to authenticate to Azure:
name: Deploy
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Azure login via OIDC
uses: actions/azure/login@v2
with:
client-id: "$AZURE_CLIENT_ID"
tenant-id: "$AZURE_TENANT_ID"
subscription-id: "$AZURE_SUBSCRIPTION_ID"
- name: Deploy
run: az webapp deploy --name "$WEBAPP_NAME" --resource-group "$RG_NAME" --src-path ./build
The actions/azure/login@v2 action fetches the OIDC token from
GitHub and exchanges it for an Azure access token by calling the
federated credential endpoint. The Azure access token is valid for
approximately one hour; the job uses it; the job ends; the token
expires.
GCP Workload Identity Federation
GCP Workload Identity Federation lets a GitHub Actions workflow exchange an OIDC token for a short-lived GCP service account access token. The configuration has four pieces:
flowchart LR
P["Workload identity pool"] --> PROV["Provider\n(GitHub OIDC issuer)"]
PROV --> SA["Service account\n(GCP IAM permissions)"]
SA --> IAM["IAM binding\n(pool subject → SA)"]
IAM --> J["google-github-actions/auth@v2\nexchanges JWT for GCP token"]
J --> AT["GCP access token\n(~1 hour)"]
- Workload identity pool. A GCP resource that holds OIDC providers. The pool is a logical grouping of external identities.
- Provider. The OIDC provider within the pool. The provider
specifies the issuer URL (
https://token.actions.githubusercontent.com) and the attribute mapping (how to translate OIDC claims to GCP attributes). - Service account. The GCP service account that the workflow impersonates. The service account has the GCP IAM permissions the workflow needs.
- IAM binding. A binding that grants the workload identity pool
subject (for example,
repo:acme/infra:ref:refs/heads/main) theroles/iam.workloadIdentityUserrole on the service account.
The pool and provider are created via gcloud:
gcloud iam workload-identity-pools create github-actions-pool \
--location global
gcloud iam workload-identity-pools providers create-oidc github-actions-provider \
--location global \
--workload-identity-pool github-actions-pool \
--issuer-url https://token.actions.githubusercontent.com \
--attribute-mapping "google.subject=assertion.sub,attribute.repository=assertion.repository"
The IAM binding grants the pool subject permission to impersonate the service account:
gcloud iam service-accounts add-iam-policy-binding "$SA_EMAIL" \
--role roles/iam.workloadIdentityUser \
--member "principalSet://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/github-actions-pool/attribute.repository/acme/infra"
The GCP workflow
A workflow that uses OIDC to authenticate to GCP:
name: Deploy
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: GCP auth via OIDC
uses: google-github-actions/auth@v2
with:
workload_identity_provider: projects/"$PROJECT_NUMBER"/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider
service_account: "$GCP_SA_EMAIL"
- name: Deploy
run: gsutil rsync -r ./build gs://"$BUCKET_NAME"
The google-github-actions/auth@v2 action fetches the OIDC token
from GitHub and exchanges it for a GCP access token by calling the
service account impersonation endpoint. The GCP access token is
valid for approximately one hour; the job uses it; the job ends; the
token expires.
Differences from AWS
The Azure and GCP models differ from AWS in three ways:
flowchart TB
subgraph AWS["AWS model"]
A1["IAM role"]
A2["Trust policy on role"]
A3["sts:AssumeRoleWithWebIdentity"]
end
subgraph AZURE["Azure model"]
Z1["App registration"]
Z2["Federated credential on app"]
Z3["OAuth token exchange"]
end
subgraph GCP["GCP model"]
G1["Service account"]
G2["Workload identity pool + provider"]
G3["Service account impersonation"]
end
- Trust location. AWS puts the trust policy on the IAM role. Azure puts the federated credential on the app registration. GCP uses a workload identity pool with a separate IAM binding to the service account.
- Exchange endpoint. AWS uses
sts:AssumeRoleWithWebIdentity. Azure uses OAuth token exchange against the federated credential endpoint. GCP uses service account impersonation against the IAM credentials endpoint. - Subject claim semantics. AWS uses
subdirectly. Azure usessubdirectly. GCP uses an attribute mapping fromsub(or other OIDC claims) to agoogle.subjectattribute; the IAM binding matches against the attribute.
The outcome is identical: a short-lived cloud credential issued per job, scoped to the workflow, and dead at job end. The mechanics differ; the structural property is the same.
Production discipline
- The federated credential or provider specifies the issuer and subject pattern. Both must match the workflow’s actual OIDC claims; both are reviewed when workflow files change.
- The audience is explicit. Azure expects
api://AzureADTokenExchange; AWS expectssts.amazonaws.com; GCP uses the provider’s audience. - The IAM binding matches the trust configuration. Azure’s
federated credential matches the workflow’s
sub; GCP’s IAM binding matches the mapped attributes. - The session duration is bounded by the job duration. A 30-minute job should not request a 12-hour token; the longer the token, the larger the replay window if the credentials leak.
Cross-course references
- Git, CI/CD & GitOps — Part XLIII-04 (OIDC in AWS) covers the
AWS-specific configuration and the
aws-actions/configure-aws-credentialsaction. - Git, CI/CD & GitOps — Part XLIII-02 (OIDC federation basics) covers the trust relationship and the JWT claim anatomy that all three clouds share.
- Git, CI/CD & GitOps — Part XLIII-06 (OIDC trust policy deep
dive) covers the
subandjob_workflow_refclaims in detail, including GitHub’s immutable subject claim change.
Quiz
Knowledge check · 4 questions
Q1. Which audience does Azure Workload Identity Federation expect in the OIDC token's `aud` claim?
Q2. GCP Workload Identity Federation requires a separate IAM binding to grant the workload identity pool subject permission to impersonate a service account.
Q3. Name the three structural differences between the AWS OIDC model and the Azure/GCP federation pool model.
Q4. Diagnose the OIDC authentication failure in GCP and prescribe the fix.
Team T configures GCP Workload Identity Federation for GitHub Actions. The workload identity pool and provider are created. The IAM binding grants the `roles/iam.workloadIdentityUser` role to `principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github-actions-pool/attribute.repository/acme/infra`. The workflow declares `id-token: write` and calls `google-github-actions/auth@v2` with the provider and service account. The action fails with: `Permission denied: the caller does not have permission to impersonate the service account`.
Passing score: 75%. Answers are checked in this browser.