Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXLIII · OIDC and Short-Lived CredentialsAzureGCP

OIDC in Azure and GCP — Workload Identity Federation; the federation pool

Advanced⏱ ~27 mingit

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

Not yet marked complete on this device.

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) the roles/iam.workloadIdentityUser role 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 sub directly. Azure uses sub directly. GCP uses an attribute mapping from sub (or other OIDC claims) to a google.subject attribute; 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

  1. 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.
  2. The audience is explicit. Azure expects api://AzureADTokenExchange; AWS expects sts.amazonaws.com; GCP uses the provider’s audience.
  3. The IAM binding matches the trust configuration. Azure’s federated credential matches the workflow’s sub; GCP’s IAM binding matches the mapped attributes.
  4. 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-credentials action.
  • 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 sub and job_workflow_ref claims in detail, including GitHub’s immutable subject claim change.

Quiz

Knowledge check · 4 questions

  1. Q1. Which audience does Azure Workload Identity Federation expect in the OIDC token's `aud` claim?

  2. Q2. GCP Workload Identity Federation requires a separate IAM binding to grant the workload identity pool subject permission to impersonate a service account.

  3. Q3. Name the three structural differences between the AWS OIDC model and the Azure/GCP federation pool model.

  4. 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.