aad-pod-identity
aad-pod-identity enables Kubernetes pods to use Azure Active Directory (Azure AD) managed identities for accessing Azure resources. Pods can authenticate to Azure services like Key Vault, Storage, and databases without storing credentials in secrets or configuration files.
This component is particularly useful for Azure Kubernetes Service (AKS) clusters but can also be deployed on self-managed Kubernetes clusters in Azure.
How It Works
- An AzureIdentity custom resource defines a managed identity.
- An AzureIdentityBinding links the identity to pods with matching labels.
- The Node Managed Identity (NMI) pods intercept Azure Instance Metadata Service (IMDS) requests.
- The Managed Identity Controller (MIC) assigns identities to nodes as needed.
- Pods receive Azure AD tokens for their assigned identity.
Prerequisites
- Azure Kubernetes Service (AKS) or Kubernetes cluster running in Azure.
- User-assigned managed identities created in Azure.
- Azure RBAC permissions configured for managed identities.
Installation
Using Helm
helm repo add aad-pod-identity https://raw.githubusercontent.com/Azure/aad-pod-identity/master/charts
helm install aad-pod-identity aad-pod-identity/aad-pod-identity --namespace kube-system
Using kubectl
kubectl apply -f https://raw.githubusercontent.com/Azure/aad-pod-identity/master/deploy/infra/deployment-rbac.yaml
Create Azure Resources
Create User-Assigned Managed Identity
# Create managed identity
az identity create \
--name my-app-identity \
--resource-group my-resource-group \
--location eastus
# Get identity client ID and resource ID
CLIENT_ID=$(az identity show --name my-app-identity --resource-group my-resource-group --query clientId -o tsv)
RESOURCE_ID=$(az identity show --name my-app-identity --resource-group my-resource-group --query id -o tsv)
Grant Azure RBAC Permissions
# Grant access to Key Vault
az keyvault set-policy \
--name my-key-vault \
--object-id $CLIENT_ID \
--secret-permissions get list
# Grant access to Storage Account
az role assignment create \
--role "Storage Blob Data Reader" \
--assignee $CLIENT_ID \
--scope /subscriptions/<subscription-id>/resourceGroups/my-resource-group/providers/Microsoft.Storage/storageAccounts/mystorageaccount
Configure Kubernetes Resources
Create AzureIdentity
apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentity
metadata:
name: my-app-identity
namespace: default
spec:
type: 0
resourceID: /subscriptions/<subscription-id>/resourcegroups/my-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/my-app-identity
clientID: <client-id-of-managed-identity>
Create AzureIdentityBinding
apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentityBinding
metadata:
name: my-app-identity-binding
namespace: default
spec:
azureIdentity: my-app-identity
selector: my-app
Deploy Pod with Identity
apiVersion: v1
kind: Pod
metadata:
name: my-app
labels:
aadpodidbinding: my-app
spec:
containers:
- name: my-app
image: my-app:latest
env:
- name: AZURE_CLIENT_ID
value: "<client-id-of-managed-identity>"
Usage in Applications
Python Example
from azure.identity import ManagedIdentityCredential
from azure.keyvault.secrets import SecretClient
# Uses pod identity automatically
credential = ManagedIdentityCredential()
client = SecretClient(
vault_url="https://my-key-vault.vault.azure.net/",
credential=credential
)
secret = client.get_secret("my-secret")
print(f"Secret value: {secret.value}")
.NET Example
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
var credential = new ManagedIdentityCredential();
var client = new SecretClient(
new Uri("https://my-key-vault.vault.azure.net/"),
credential
);
KeyVaultSecret secret = await client.GetSecretAsync("my-secret");
Console.WriteLine($"Secret value: {secret.Value}");
Security Best Practices
Restrict Identity Assignment
Use AzureIdentityBinding with specific namespaces:
apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentityBinding
metadata:
name: my-app-identity-binding
namespace: production # Only pods in this namespace can use this binding
spec:
azureIdentity: my-app-identity
selector: my-app
Use Exception Lists
Prevent pods from using certain identities:
apiVersion: aadpodidentity.k8s.io/v1
kind: AzurePodIdentityException
metadata:
name: mic-exception
namespace: kube-system
spec:
podLabels:
app: mic
component: mic
Monitor Identity Usage
Enable Azure Monitor logging:
az monitor diagnostic-settings create \
--name pod-identity-logs \
--resource $RESOURCE_ID \
--logs '[{"category": "Audit", "enabled": true}]' \
--workspace <log-analytics-workspace-id>
Migration to Workload Identity
Microsoft recommends migrating to Azure AD Workload Identity, which is the successor to aad-pod-identity:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app
annotations:
azure.workload.identity/client-id: "<client-id>"
Workload Identity advantages:
- Uses OIDC federation instead of IMDS interception.
- No privileged pods required.
- Better security isolation.
- Native AKS integration.
Troubleshooting
Check MIC Logs
kubectl logs -n kube-system -l app.kubernetes.io/component=mic
Check NMI Logs
kubectl logs -n kube-system -l app.kubernetes.io/component=nmi
Verify Identity Assignment
kubectl describe azureidentity my-app-identity
kubectl describe azureidentitybinding my-app-identity-binding
References
This article is based on information from the following official sources:
- aad-pod-identity GitHub Repository - Microsoft Azure
- Use Azure AD Pod Identity - Microsoft Documentation
- Azure AD Workload Identity - Microsoft Documentation