Federation eliminates the last long-lived secrets: CI/CD service principal passwords and pod credentials.
Managed identities only work for code running on Azure resources. Workload identity federation covers everything else that can present an OIDC token: GitHub Actions, GitLab, Kubernetes service accounts (including AKS), Google Cloud and AWS workloads.
You add a federated identity credential to a user-assigned managed identity or an app registration. It names a trusted issuer (e.g. https://token.actions.githubusercontent.com), an exact subject (e.g. repo:contoso/orders:environment:prod) and the audience api://AzureADTokenExchange. At runtime the workload gets a short-lived token from its own issuer and exchanges it at Entra ID (client credentials flow with a client_assertion) for an Entra access token. Nothing secret is stored anywhere.
Subjects must match exactly (flexible claim matching exists in preview for some issuers), so design them deliberately: binding to a GitHub environment lets you add required reviewers before production credentials are usable. An identity has a limit of 20 federated credentials.
On AKS, enable the OIDC issuer and workload identity, annotate a Kubernetes service account with the identity's client ID, label pods with azure.workload.identity/use: "true", and create a federated credential whose subject is system:serviceaccount:<namespace>:<name>. The webhook injects environment variables and a projected token file that DefaultAzureCredential picks up automatically.
Example
# One-time setup (bash):
# az identity federated-credential create -g rg-id --identity-name id-orders-deployer \
# --name gh-prod --issuer https://token.actions.githubusercontent.com \
# --subject repo:contoso/orders:environment:prod --audiences api://AzureADTokenExchange
# .github/workflows/deploy.yml
name: deploy
on: { push: { branches: [main] } }
permissions:
id-token: write # allow requesting the GitHub OIDC token
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
environment: prod # subject becomes repo:contoso/orders:environment:prod
steps:
- uses: actions/checkout@v4
- uses: azure/login@v2
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ vars.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
- run: az deployment group create -g rg-orders-prod -f main.bicepRemember
- Federation trusts an external OIDC issuer + exact subject; no secret is stored
- Works for CI/CD, Kubernetes pods and other clouds
- Scope subjects to environments or branches deliberately
- AKS: OIDC issuer + annotated service account + pod label
Watch out for
- Forgetting
permissions: id-token: writein GitHub Actions, so no OIDC token can be requested. - Using a broad subject pattern that lets any branch or fork obtain production credentials.