Migrate Azure Kubernetes Service (AKS) pods from pod-managed identity to Microsoft Entra Workload ID

Migrate AKS pods from pod-managed identities to Microsoft Entra Workload ID (workload identity) using one of three approaches based on your current Azure Identity SDK version: latest SDK parallel deployment, migration sidecar proxy (Linux only), or SDK rewrite.

Prerequisites

  • Azure CLI version 2.47.0 or later. Run the az --version command to find the version. If you need to install or upgrade, see Install Azure CLI.

Set environment variables

The following table lists the environment variables used in the commands throughout this article. Make sure to replace the placeholder values with your own values.

Environment variable Description Example value
SUBSCRIPTION_ID The ID of the Azure subscription where the AKS cluster and managed identity are created. 00000000-0000-0000-0000-000000000000
RESOURCE_GROUP The name of the resource group where the AKS cluster and managed identity are created. myResourceGroup
LOCATION The Azure region where the AKS cluster and managed identity are created. chinanorth3
CLUSTER_NAME The name of the AKS cluster. myAKSCluster
MANAGED_IDENTITY_NAME The name of the user-assigned managed identity. myManagedIdentity
SERVICE_ACCOUNT_NAME The name of the Kubernetes service account to create or associate with the managed identity. workload-identity-sa
SERVICE_ACCOUNT_NAMESPACE The namespace of the Kubernetes service account. default
FEDERATED_IDENTITY_NAME The name of the federated identity credential to create. myFederatedIdentity

Choose a migration path

Select the appropriate migration approach based on your current Azure Identity SDK version:

  • Latest Azure Identity SDK: If your application already uses the latest version of Azure Identity SDK, you can migrate by deploying Microsoft Entra Workload ID in parallel with existing pod-managed identity.
  • Older SDK with migration sidecar - If your application uses an older SDK version and runs on Linux containers, you can use a temporary migration sidecar to proxy Instance Metadata Service (IMDS) transactions while planning your SDK upgrade.
  • Older SDK rewrite approach: If your application uses an older SDK version, you can update your application code to use the latest Azure Identity SDK, then migrate to workload identity.

Prepare for migration

For all migration paths, you need to have the federated trust set up before you update your application to use Microsoft Entra Workload ID. The following are the minimum steps required:

Migrate from latest version of Azure Identity SDK

This migration path applies when your application already uses the latest version of the Azure Identity SDK and you want to migrate with minimal code changes.

Migration approach: Deploy Microsoft Entra Workload ID in parallel with pod-managed identity, verify functionality, then remove pod-managed identity.

Steps:

  1. Deploy Microsoft Entra Workload ID in parallel with existing pod-managed identity.
  2. Restart your application deployment to begin using Microsoft Entra Workload ID (OIDC annotations are injected automatically).
  3. Verify the application can authenticate successfully using workload identity.
  4. Remove the pod-managed identity annotations from your application.
  5. Remove the pod-managed identity add-on from your cluster.

Use a migration sidecar (Linux containers only)

This migration path applies when your application uses an older version of the Azure Identity SDK, runs on Linux containers, and you need a temporary solution while planning SDK updates.

Migration approach: Deploy a migration sidecar that proxies IMDS transactions to OIDC, allowing your existing application code to work without immediate changes.

Important limitations:

  • Linux containers only. Windows containers aren't supported.
  • Temporary solution that's not intended for long-term production use.
  • Planning required to schedule SDK updates for long-term support.

Steps:

  1. Deploy the workload with migration sidecar to proxy IMDS transactions.
  2. Verify authentication transactions complete successfully.
  3. Schedule application SDK updates to supported Azure Identity versions.
  4. Once SDKs are updated, remove the proxy sidecar and redeploy applications.

Rewrite application for latest Azure Identity SDK

This migration path applies when your application uses an older version of the Azure Identity SDK and you want to update to the latest supported SDK before migrating.

Migration approach: Update your application code to use the latest Azure Identity SDK, then migrate to Microsoft Entra Workload ID with the updated code.

Technical outcomes:

  • Uses current Azure Identity SDK versions (no deprecation timeline).
  • Supports both Linux and Windows containers (unlike sidecar approach).
  • Eliminates proxy components and IMDS translation overhead.

Steps:

  1. Update your application code to use the latest Azure Identity SDK.
  2. Test the updated application with pod-managed identity.
  3. Restart your application deployment to begin authenticating using Microsoft Entra Workload ID (OIDC annotations are injected automatically).
  4. Verify authentication transactions complete successfully.
  5. Remove the pod-managed identity annotations and add-on.

Set an active Azure subscription

  • Set a specific Azure subscription as the current active subscription using the az account set command.

    az account set --subscription $SUBSCRIPTION_ID
    

Create a managed identity

  • Create a managed identity using the az identity create command.

    az identity create --name $MANAGED_IDENTITY_NAME --resource-group $RESOURCE_GROUP --location $LOCATION --subscription $SUBSCRIPTION_ID
    

Get managed identity client ID

  • Get the client ID of the managed identity and save it to an environmental variable using the az identity show command.

    export USER_ASSIGNED_CLIENT_ID="$(az identity show --resource-group $RESOURCE_GROUP --name $MANAGED_IDENTITY_NAME --query 'clientId' -otsv)"
    

Grant managed identity access to Azure resources

Get OIDC issuer URL

  • Get the OIDC issuer URL and save it to an environmental variable using the az aks show command.

    export AKS_OIDC_ISSUER="$(az aks show --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP --query "oidcIssuerProfile.issuerUrl" -o tsv)"
    

    The variable should contain an issuer URL similar to the following example:

    https://eastus.oic.prod-aks.azure.com/00000000-0000-0000-0000-000000000000/00000000-0000-0000-0000-000000000000/
    

    By default, the issuer uses the base URL https://{region}.oic.prod-aks.azure.com/{uuid}, where the value for {region} matches the location the AKS cluster is deployed in. The value {uuid} represents the OIDC key.

Get AKS cluster credentials

  • Get the AKS cluster credentials using the az aks get-credentials command.

    az aks get-credentials --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP
    

Create Kubernetes service account

  • Create a Kubernetes service account and annotate it with the managed identity client ID using the kubectl apply command. Make sure to replace the placeholder values with your own values.

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      annotations:
        azure.workload.identity/client-id: ${USER_ASSIGNED_CLIENT_ID}
      name: ${SERVICE_ACCOUNT_NAME}
      namespace: ${SERVICE_ACCOUNT_NAMESPACE}
    EOF
    

    The following output resembles successful creation of the identity:

    Serviceaccount/workload-identity-sa created
    

Establish federated identity credential trust

  • Create the federated identity credential between the managed identity, service account issuer, and subject using the az identity federated-credential create command.

    az identity federated-credential create --name $FEDERATED_IDENTITY_NAME --identity-name $MANAGED_IDENTITY_NAME --resource-group $RESOURCE_GROUP --issuer ${AKS_OIDC_ISSUER} --subject system:serviceaccount:${SERVICE_ACCOUNT_NAMESPACE}:${SERVICE_ACCOUNT_NAME} --audience api://AzureADTokenExchange
    

    The federated identity credential takes a few minutes to propagate after being added. If a token request is made immediately after adding the federated identity credential, the token request might fail because the Azure AD directory cache contains outdated information.

Deploy the workload with migration sidecar

If your application uses user-assigned managed identity and still relies on IMDS to get an access token you can use the migration sidecar to start migrating to Microsoft Entra Workload ID. In long-term applications, you should modify the code to use the latest Azure Identity SDKs that support client assertion.

To update or deploy the workload, add the following pod annotations to your pod specification (only if you want to use the migration sidecar):

Pod annotation Description Value
azure.workload.identity/inject-proxy-sidecar Indicates whether to inject the proxy sidecar into the pod. true or false
azure.workload.identity/proxy-sidecar-port Desired port for the proxy sidecar. Default value: 8000

When you create a pod with these annotations, the Microsoft Entra Workload ID mutating webhook automatically injects the init-container and proxy sidecar to the pod spec. The following YAML shows an example of what the mutating webhook adds to the pod deployment:

apiVersion: v1
kind: Pod
metadata:
  name: httpbin-pod
  labels:
    app: httpbin
    azure.workload.identity/use: "true"
  annotations:
    azure.workload.identity/inject-proxy-sidecar: "true"
spec:
  serviceAccountName: workload-identity-sa
  initContainers:
  - name: init-networking
    image: mcr.azk8s.cn/oss/azure/workload-identity/proxy-init:v1.1.0
    securityContext:
      capabilities:
        add:
        - NET_ADMIN
        drop:
        - ALL
      privileged: true
      runAsUser: 0
    env:
    - name: PROXY_PORT
      value: "8000"
  containers:
  - name: nginx
    image: nginx:alpine
    ports:
    - containerPort: 80
  - name: proxy
    image: mcr.azk8s.cn/oss/azure/workload-identity/proxy:v1.1.0
    ports:
    - containerPort: 8000

Verify the workload with migration sidecar

  1. Verify the pod is in a running state using the kubectl describe pod command. Replace <pod-name> with the name of your pod.

    kubectl describe pods <pod-name>
    
  2. Verify the pod is passing IMDS transactions using the kubectl logs command. Replace <pod-name> with the name of your pod.

    kubectl logs <pod-name>
    

    The following example log output resembles successful communication through the proxy sidecar. Verify the logs show a token is successfully acquired and the GET operation is successful.

    I0926 00:29:29.968723       1 proxy.go:97] proxy "msg"="starting the proxy server" "port"=8080 "userAgent"="azure-workload-identity/proxy/v0.13.0-12-gc8527f3 (linux/amd64) c8527f3/2022-09-26-00:19"
    I0926 00:29:29.972496       1 proxy.go:173] proxy "msg"="received readyz request" "method"="GET" "uri"="/readyz"
    I0926 00:29:30.936769       1 proxy.go:107] proxy "msg"="received token request" "method"="GET" "uri"="/metadata/identity/oauth2/token?resource=https://management.core.chinacloudapi.cn/api-version=2018-02-01&client_id=<client_id>"
    I0926 00:29:31.101998       1 proxy.go:129] proxy "msg"="successfully acquired token" "method"="GET" "uri"="/metadata/identity/oauth2/token?resource=https://management.core.chinacloudapi.cn/api-version=2018-02-01&client_id=<client_id>"
    

Remove pod-managed identity

After you complete your testing and the application can successfully get a token using the proxy sidecar, you can remove the identity and pod-managed identity mapping from your AKS cluster

  • Remove the pod-managed identity binding from your pod using the az aks pod-identity delete command. Replace <pod-identity-name> and <pod-identity-namespace> with the name and namespace of your pod identity.

    az aks pod-identity delete --name <pod-identity-name> --namespace <pod-identity-namespace> --resource-group $RESOURCE_GROUP --cluster-name $CLUSTER_NAME
    

For more information about Microsoft Entra Workload ID, see the Overview article.