Azure Workload Identity
Microsoft Entra Workload ID (formerly Azure Workload Identity) lets Kubernetes pods authenticate to Azure resources without storing credentials. Pods use a Kubernetes service account token, which is exchanged for an Azure token via OIDC.
How It Works
- You annotate a Kubernetes ServiceAccount with the Azure Managed Identity client ID
- Pods using that ServiceAccount get a projected token volume
- The Azure Identity SDK or MSAL exchanges the token for an Azure access token
- Your app authenticates to Key Vault, Storage, etc., with no secrets in the cluster
Prerequisites
- AKS 1.22+
- Azure CLI 2.47+
- User-assigned Managed Identity
- OIDC issuer enabled on the cluster
Enable Workload Identity on AKS
az aks update \
--resource-group <your-resource-group> \
--name <your-aks-cluster> \
--enable-oidc-issuer \
--enable-workload-identity
Create Managed Identity
az identity create \
--resource-group <your-resource-group> \
--name <your-workload-identity>
# Get client ID
az identity show \
--resource-group <your-resource-group> \
--name <your-workload-identity> \
--query clientId -o tsv
Create Federated Credential
Link the Kubernetes ServiceAccount to the Azure Managed Identity:
az identity federated-credential create \
--name <credential-name> \
--identity-name <your-workload-identity> \
--resource-group <your-resource-group> \
--issuer <aks-oidc-issuer-url> \
--subject system:serviceaccount:<namespace>:<service-account-name> \
--audience api://AzureADTokenExchange
Get the OIDC issuer URL:
az aks show \
--resource-group <your-resource-group> \
--name <your-aks-cluster> \
--query "oidcIssuerProfile.issuerUrl" -o tsv
ServiceAccount Annotations
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: my-namespace
annotations:
azure.workload.identity/client-id: "<managed-identity-client-id>"
azure.workload.identity/use: "true"
Pod Label
Pods must have this label for the mutating webhook to inject tokens:
labels:
azure.workload.identity/use: "true"
Grant Key Vault Access
az role assignment create \
--assignee <managed-identity-principal-id> \
--role "Key Vault Secrets User" \
--scope /subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault-name>