k8s Azure OIDC Federated Microsoft Entra Workload ID
- 2026 - Way to assign identity to individual POD's
Set k8s AKS values
export AZ_RG="dev-kubernetes-rg" export AZ_AKS="z-dev-kubernetes-01-aks-SGmrd5"
Check for old Azure identities pre OIDC
az cli old identity's
az aks pod-identity list --cluster-name ${AZ_AKS} --resource-group ${AZ_RG}kubctl old crd's
kubectl get azureidentity,azureidentitybinding --all-namespaces
az cli - check identity used by AKS cluster
AKS identity
az aks show --resource-group ${AZ_RG} --name ${AZ_AKS} --query "identity"- Exprect to get one entry with "type": "userAssigned"
az cli - new oidc and workload identity enabled for aks
az cli
az aks show --resource-group ${AZ_RG} --name ${AZ_AKS} --query "{ workloadIdentityEnabled: securityProfile.workloadIdentity.enabled, oidcIssuerEnabled: oidcIssuerProfile.enabled, oidcIssuerUrl: oidcIssuerProfile.issuerUrl }" --output yaml
view all AKS ServiceAccounts with workload identity annotations/labels
A - from AKS using kubectl
kubectl
kubectl get sa --all-namespaces \ -o json | jq -r '.items[] | select(.metadata.annotations["azure.workload.identity/client-id"] != null or .metadata.labels["azure.workload.identity/use"] != null) | "Namespace: \(.metadata.namespace) SA: \(.metadata.name) client-id: \(.metadata.annotations["azure.workload.identity/client-id"] // "n/a")"'
B - from Azure using cli
get oidc issuer
AKS_OIDC_ISSUER=$(az aks show -g ${AZ_RG} -n ${AZ_AKS} --query oidcIssuerProfile.issuerUrl -o tsv) echo $AKS_OIDC_ISSUERthen search for federated credentials
az identity list --resource-group <rg-where-identities-live> --query "[?federatedCredentials[?issuer=='$AKS_OIDC_ISSUER']]" --output table
Or script a broader search (requires sufficient permissions):
for id in $(az identity list --query [].id -o tsv); do az identity federated-credential list --ids $id --query "[?issuer=='$AKS_OIDC_ISSUER'].{name:name, subject:subject, clientId:parentPrincipalId}" -o table done
How to create Entra Identity
Create ManagedIdentity (No password)
az identity create --name myWorkloadId --resource-group myRg --location eastus
assign role's
az role assignment create --assignee <principalId> --role "Key Vault Secrets User" --scope <kv-resource-id>
create the federated identity credential on the managed identity:
az identity federated-credential create \ --name "fed-cred-backend" \ --identity-name myWorkloadId \ --resource-group myRg \ --issuer "<your-aks-oidc-issuer-url>" \ --subject "system:serviceaccount:finance:backend-sa" \ --audience "api://AzureADTokenExchange"
- → This links the Kubernetes Service Account → AKS issuer → the managed identity's service principal.
Explain: --subjet - follows Kubernetes' standard format for identifying a ServiceAccount in a JWT token's sub (subject) claim.
system:serviceaccount: This is a fixed prefix used by Kubernetes for all ServiceAccount-based subjects
finance: This is the Kubernetes namespace where the ServiceAccount lives
backend-sa: This is the actual name of the Kubernetes ServiceAccount resource e.g.
kubectl create serviceaccount backend-sa -n finance
for AKS + Workload ID it's always this system:serviceaccount:<namespace>:<sa-name> pattern.
→ create/annotate K8s SA → Pod starts using that ServiceAccount → mutating webhook injects env vars → pod requests token from Microsoft identity platform using federation flow → gets access token scoped as the service principal.
