= 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_ISSUER }}} * then search for federated credentials {{{ az identity list --resource-group --query "[?federatedCredentials[?issuer=='$AKS_OIDC_ISSUER']]" --output table }}} * Or script a broader search (requires sufficient permissions): {{{#! highlight bash 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 == 1. Create !ManagedIdentity (No password) {{{ az identity create --name myWorkloadId --resource-group myRg --location eastus }}} 2. assign role's {{{ az role assignment create --assignee --role "Key Vault Secrets User" --scope }}} 3. 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 "" \ --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:: pattern. 4. → 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. ---- CategoryK8sKubernetes CategorySecurity