Kubernetes workloads can now assume cloud provider identities without needing service account tokens or secrets, which is a massive security win.

Let’s say you have an Azure Kubernetes Service (AKS) cluster and you want a pod running in that cluster to access Azure Key Vault. Traditionally, you’d have a few options, none of them ideal:

  1. Kubernetes Secrets: Create a Kubernetes Secret containing the Azure AD application credentials (client ID and client secret) for a service principal. Mount this secret as a file into the pod. This means the secret is stored in etcd and potentially exposed if the pod is compromised.
  2. Managed Identity (older way): Configure your AKS cluster to use a user-assigned managed identity, and then assign that identity to pods that need to access Azure resources. This is better, but still involves some cluster-level configuration and doesn’t give granular identity per pod.

Workload Identity Federation changes this. It allows your Kubernetes pods to directly impersonate an Azure AD service principal (or even a user identity) without ever needing to manage Azure AD credentials within Kubernetes. The core idea is that Kubernetes (specifically, the service account used by the pod) issues a signed token that Azure AD trusts, and Azure AD then issues a short-lived Azure AD token in exchange.

Here’s how it works in practice with AKS:

First, you need to set up the Azure AD side.

  1. Create an Azure AD Application Registration: This represents the identity your Kubernetes workload will impersonate.

    # Log in to Azure CLI
    az login
    
    # Create a new Azure AD application registration
    az ad app create --display-name aks-workload-identity-app --null-id
    APP_ID=$(az ad app list --display-name aks-workload-identity-app --query "[].appId" -o tsv)
    echo "Application (client) ID: $APP_ID"
    
    # Create a client secret for the application (this is what the pod will exchange its K8s token for)
    az ad app credential reset --id $APP_ID --append --display-name aks-workload-identity-app-secret
    CLIENT_SECRET=$(az ad app credential list --id $APP_ID --query "[].secretText" -o tsv)
    echo "Client Secret: $CLIENT_SECRET"
    
    # Create a service principal for the application
    az ad sp create --id $APP_ID
    SP_ID=$(az ad sp list --display-name aks-workload-identity-app --query "[].id" -o tsv)
    echo "Service Principal ID: $SP_ID"
    

    You’ll get an APP_ID and a CLIENT_SECRET. The APP_ID is what your pod will request a token for. The CLIENT_SECRET is what the pod will use to exchange its Kubernetes token for an Azure AD token. This is a crucial distinction.

  2. Grant Permissions to the Service Principal: Now, grant this service principal the necessary permissions to the Azure resource it needs to access. For example, to access Key Vault:

    # Get your subscription ID
    SUBSCRIPTION_ID=$(az account show --query id -o tsv)
    
    # Get your resource group name (replace with your actual resource group)
    RESOURCE_GROUP_NAME="my-aks-rg"
    
    # Get Key Vault name (replace with your actual Key Vault name)
    KEY_VAULT_NAME="my-aks-kv"
    
    # Assign "Key Vault Secrets Officer" role to the service principal
    az role assignment create --role "Key Vault Secrets Officer" --assignee $SP_ID --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEY_VAULT_NAME"
    

Next, you need to configure AKS to enable Workload Identity and link your Kubernetes Service Account to the Azure AD application.

  1. Enable Workload Identity on AKS:

    # Get your AKS cluster name and resource group
    AKS_CLUSTER_NAME="my-aks-cluster"
    AKS_RESOURCE_GROUP="my-aks-rg" # Same RG as Key Vault, or wherever your AKS is
    
    # Enable Workload Identity on the AKS cluster
    az aks update --name $AKS_CLUSTER_NAME --resource-group $AKS_RESOURCE_GROUP --enable-workload-identity
    

    This command installs the necessary components into your cluster.

  2. Create a Kubernetes Service Account: This is the identity your pod will use.

    # Create a Kubernetes namespace if it doesn't exist
    kubectl create namespace my-app-ns
    
    # Create a Kubernetes Service Account
    kubectl create serviceaccount my-app-sa -n my-app-ns
    
  3. Create a Workload Identity Binding: This is the key piece that links the Kubernetes Service Account to the Azure AD Application.

    # Get the Azure AD Application (client) ID
    APP_ID="<your-app-id>" # From step 1
    
    # Get the Azure AD Tenant ID
    TENANT_ID=$(az account show --query tenantId -o tsv)
    
    # Create the Workload Identity binding
    cat <<EOF | kubectl apply -f -
    apiVersion: aadpodidentity.k8s.io/v1
    kind: WorkloadIdentity
    metadata:
      name: aks-workload-identity-binding
      namespace: my-app-ns
    spec:
      serviceAccount:
        name: my-app-sa
        namespace: my-app-ns
      azureIdentity:
        type: application
        resourceID: "/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${AKS_RESOURCE_GROUP}/providers/Microsoft.AAD/applications/${APP_ID}" # This is the Azure AD Application ID
        type: servicePrincipal # This is important for App Registration identities
    EOF
    

    Correction: The WorkloadIdentity CRD is deprecated. You should use AzureIdentity and AzureIdentityBinding instead. Let’s correct that.

    Corrected Step 5: First, create an AzureIdentity resource that references your Azure AD application.

    # Get the Azure AD Application (client) ID
    APP_ID="<your-app-id>" # From step 1
    
    # Get the Azure AD Tenant ID
    TENANT_ID=$(az account show --query tenantId -o tsv)
    
    # Create the AzureIdentity resource
    cat <<EOF | kubectl apply -f -
    apiVersion: aadpodidentity.k8s.io/v1
    kind: AzureIdentity
    metadata:
      name: my-azure-identity
      namespace: my-app-ns
    spec:
      type: application
      resourceID: "/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${AKS_RESOURCE_GROUP}/providers/Microsoft.AAD/applications/${APP_ID}"
      clientID: "${APP_ID}"
      tenantID: "${TENANT_ID}"
    EOF
    

    Then, create an AzureIdentityBinding to link the AzureIdentity to the Kubernetes ServiceAccount.

    # Create the AzureIdentityBinding resource
    cat <<EOF | kubectl apply -f -
    apiVersion: aadpodidentity.k8s.io/v1
    kind: AzureIdentityBinding
    metadata:
      name: my-azure-identity-binding
      namespace: my-app-ns
    spec:
      azureIdentity:
        name: my-azure-identity
        namespace: my-app-ns
      serviceAccount:
        name: my-app-sa
        namespace: my-app-ns
    EOF
    

Now, configure your pod to use this Service Account.

  1. Deploy your Pod: In your pod’s YAML, specify the serviceAccountName to be the one you created.
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-app-pod
      namespace: my-app-ns
    spec:
      serviceAccountName: my-app-sa # This is the K8s Service Account
      containers:
      - name: app-container
        image: mcr.microsoft.com/azuredocs/azure-cli:latest # Example image that can run Azure CLI commands
        command: ["/bin/sh", "-c", "sleep infinity"]
    
    Apply this YAML: kubectl apply -f your-pod.yaml

The magic happens when your application code, running inside the pod, uses an Azure SDK or the Azure CLI. The Azure SDKs (when configured correctly, typically by setting AZURE_FEDERATED_TOKEN_FILE and AZURE_CLIENT_ID environment variables) will automatically:

  1. Discover the Kubernetes Service Account it’s running as.
  2. Locate the aadpodidentity.k8s.io/v1 secrets containing the Kubernetes token (usually mounted at /var/run/secrets/tokens/) and the Azure AD clientID and tenantID (from the AzureIdentity CR).
  3. Exchange the Kubernetes Service Account token for an Azure AD token by making a POST request to the Azure AD token endpoint, proving its identity.
  4. Use the obtained Azure AD token to authenticate with Azure services.

The core mechanism is that the aad-pod-identity add-on (installed by az aks update --enable-workload-identity) injects a mutated AzureIdentity and AzureIdentityBinding into the pod’s service account, providing the necessary environment variables (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_FEDERATED_TOKEN_FILE) and a volume mount for the Kubernetes token. The Azure SDK then uses these to perform the token exchange.

The most surprising part of this is how seamlessly the Azure SDKs abstract away the token exchange. You don’t write any code to call Azure AD directly; the SDK handles the https://login.microsoftonline.com/<tenant_id>/oauth2/v2.0/token endpoint using the provided Kubernetes token as a client_assertion.

The next step after successfully federating identities is to manage secrets securely.

Want structured learning?

Take the full Aks course →