AKS managed identity errors occur when pods fail to authenticate to Azure services because the managed identity is not properly configured, accessible, or lacks required RBAC permissions. These errors prevent your applications from accessing Azure resources like Key Vault, databases, and storage.
In Azure Kubernetes Service (AKS), managed identities enable pods to authenticate to Azure services without storing credentials in code or Kubernetes secrets. When an AKS managed identity error occurs, it means the pod cannot obtain a token from the Azure Instance Metadata Service (IMDS) endpoint at 169.254.169.254. This happens when the identity is misconfigured, the Node Managed Identity (NMI) pods are not intercepting requests correctly, or the identity lacks permission to access the target Azure resource. AKS supports two managed identity approaches: the legacy pod-managed identity (deprecated as of October 2022) and the modern workload identity, which uses OIDC federation with Kubernetes service accounts. Most AKS clusters now use workload identity for better security and native Kubernetes integration.
Check if your cluster has workload identity enabled:
az aks show --resource-group myResourceGroup --name myAKSCluster --query oidcIssuerProfile.enabledIf output is false or null, enable it:
az aks update --resource-group myResourceGroup --name myAKSCluster --enable-oidc-issuerAfter enabling, update the OIDC issuer URL in your Kubernetes configurations if you have existing ones.
Get the OIDC issuer URL from your cluster:
az aks show --resource-group myResourceGroup --name myAKSCluster --query oidcIssuerProfile.issuerUrl --output tsvExample output: https://oidc.prod-aks.azure.com/12345678-1234-1234-1234-123456789012/
From a pod, verify you can reach this endpoint:
kubectl run -it --rm debug --image=curlimages/curl --restart=Never -- curl https://oidc.prod-aks.azure.com/12345678-1234-1234-1234-123456789012/.well-known/openid-configurationIf the request fails, the cluster network is blocking access. Check network policies and firewall rules.
Create a federated identity credential linking your Kubernetes service account to a managed identity:
az identity federated-credential create \
--resource-group myResourceGroup \
--identity-name myManagedIdentity \
--name myFederatedCred \
--issuer https://oidc.prod-aks.azure.com/12345678-1234-1234-1234-123456789012/ \
--subject system:serviceaccount:default:myServiceAccountCritical: The issuer URL must have a trailing slash and match exactly (check for typos, special characters, or missing path).
Verify the credential was created:
az identity federated-credential show \
--resource-group myResourceGroup \
--identity-name myManagedIdentity \
--name myFederatedCredUpdate your pod YAML to include the workload identity configuration:
apiVersion: v1
kind: ServiceAccount
metadata:
name: myServiceAccount
namespace: default
annotations:
azure.workload.identity/client-id: "12345678-1234-1234-1234-123456789abc"
---
apiVersion: v1
kind: Pod
metadata:
name: myapp
namespace: default
spec:
serviceAccountName: myServiceAccount
labels:
azure.workload.identity/use: "true" # Critical label
containers:
- name: app
image: myapp:latest
env:
- name: AZURE_CLIENT_ID
value: "12345678-1234-1234-1234-123456789abc"
- name: AZURE_TENANT_ID
value: "12345678-1234-1234-1234-123456789def"
- name: AZURE_AUTHORITY_HOST
value: "https://login.microsoftonline.com"The label azure.workload.identity/use: "true" tells AKS to enable workload identity for this pod.
The managed identity must have appropriate roles on the resource it needs to access. For example, accessing Key Vault:
az keyvault set-policy --name myKeyVault \
--object-id $(az identity show --resource-group myResourceGroup --name myManagedIdentity --query principalId -o tsv) \
--secret-permissions get list \
--key-permissions get listFor other resources:
- Storage Account: Assign "Storage Blob Data Reader" role
- SQL Database: Ensure managed identity is added as database user with appropriate permissions
- Container Registry: Assign "AcrPull" role
Check current role assignments:
az role assignment list --scope /subscriptions/mySubscription/resourceGroups/myResourceGroup \
--assignee-object-id $(az identity show --resource-group myResourceGroup --name myManagedIdentity --query principalId -o tsv)By default, pods reach IMDS at 169.254.169.254:80. Verify network connectivity:
kubectl run -it --rm debug --image=busybox --restart=Never -- wget -O- http://169.254.169.254/metadata/identity/oauth2/token?api-version=2017-09-01If this times out or fails:
- Check pod network policies: kubectl get networkpolicies -A
- Verify node can reach IMDS: SSH to node and run the same wget command
- For custom CNI plugins, ensure they do not block link-local traffic to 169.254.169.254
If using Azure Firewall or restrictive NSGs, allow outbound traffic to the IMDS endpoint.
Update your application code to use Azure SDKs with workload identity. Most Azure SDKs (Python, .NET, Node.js, Go) support the DefaultAzureCredential pattern:
Python (azure-identity package):
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
credential = DefaultAzureCredential()
secret_client = SecretClient(vault_url="https://myvault.vault.azure.net/", credential=credential)Node.js:
const { DefaultAzureCredential } = require("@azure/identity");
const { SecretClient } = require("@azure/keyvault-secrets");
const credential = new DefaultAzureCredential();
const client = new SecretClient("https://myvault.vault.azure.net/", credential);The DefaultAzureCredential automatically detects the workload identity environment variables (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_AUTHORITY_HOST) and uses them to authenticate.
If using the Azure Secrets Store CSI Driver, ensure it is configured for workload identity (not legacy pod-managed identity):
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: azure-secrets
spec:
provider: azure
parameters:
usePodIdentity: "false" # Disable legacy pod-managed identity
useVMManagedIdentity: "false" # Disable VM-based identity
clientID: "12345678-1234-1234-1234-123456789abc" # Workload identity client ID
keyvaultName: myVault
objects: |
array:
- |
objectName: mySecret
objectType: secret
objectVersion: ""
tenantID: "12345678-1234-1234-1234-123456789def"Then reference in your pod spec:
volumes:
- name: secrets-store
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "azure-secrets"The older pod-managed identity (open-source Microsoft Entra pod-managed identity) was deprecated October 24, 2022 and the project archived in September 2023. New clusters should use workload identity exclusively. If migrating from legacy pod-managed identity, you must remove MIC and NMI deployments and reconfigure with federated credentials and service account annotations. For compliance scenarios requiring Fail Close behavior, ensure the label azure.workload.identity/use: "true" is always present on pods needing identity—without it, pods will not receive the projected OIDC token. In CI/CD pipelines (GitHub Actions, Azure Pipelines), workload identity federation can be configured at the GitHub Actions runner or Pipelines service connection level instead of pod level. For debugging, check AKS system pod logs: kubectl logs -n kube-system -l app=azure-workload-identity-webhook. Token file permissions changed in Kubernetes 1.19 from 0600 to 0644, allowing non-root containers to read tokens. Monitor token refresh rates in your application—tokens are short-lived by design and should be obtained fresh before each API call.
Failed to connect to server: connection refused (HTTP/2)
How to fix "HTTP/2 connection refused" error in Kubernetes
missing request for cpu in container
How to fix "missing request for cpu in container" in Kubernetes HPA
error: invalid configuration
How to fix "error: invalid configuration" in Kubernetes
etcdserver: cluster ID mismatch
How to fix "etcdserver: cluster ID mismatch" in Kubernetes
running with swap on is not supported
How to fix "running with swap on is not supported" in kubeadm