Azure Workload Identity: A Step-by-Step Implementation Guide
TL;DR
- ✓ Replace risky hardcoded service principal secrets with secure OIDC federation tokens.
- ✓ Learn how to map Kubernetes service accounts to Azure managed identities effectively.
- ✓ Implement least-privilege access for AKS pods using temporary machine identity tokens.
- ✓ Follow prerequisites including AKS version requirements and necessary Azure CLI permissions.
If you’re still hardcoding service principal secrets into your Kubernetes manifests, stop. You’re sitting on a security time bomb. The industry has moved on from long-lived client secrets for one simple reason: static credentials leak. It’s not a matter of if, but when.
Azure Workload Identity is the fix. It’s a "secret-less" way to give your AKS pods temporary, least-privilege access to Azure resources via OIDC federation. When you make this switch, you’re aligning with best practices for secure machine identities. You trade credentials that last for years for tokens that expire in minutes. It’s a massive upgrade.
Why Secrets Are a Liability
Think about the old way: you create a Service Principal, generate a client secret, and stuff it into a Kubernetes Secret. Security nightmare. Once that secret hits etcd, anyone with read access to the cluster state can see it. And if a developer accidentally pushes that manifest to a public Git repo? You’re looking at a full-blown incident.
Workload Identity flips the script. The pod doesn’t "know" a secret. Instead, it presents an OIDC token issued by the AKS cluster to Microsoft Entra ID. Entra ID validates that token, checks the federated identity, and hands back a temporary Azure access token. It’s a handshake, not a handoff. No secrets, no exposure.
How Azure Workload Identity Works
The magic is in the OIDC federation. When your pod needs to touch an Azure resource, it doesn’t go hunting for environment variables containing passwords. It uses the Azure Identity SDK to grab a token.
The relationship is straightforward: a Kubernetes Service Account gets mapped to an Entra ID Managed Identity through a "Federated Identity Credential." You’re essentially telling Azure: "If this pod proves its identity via the AKS OIDC issuer, treat it like this specific Managed Identity."
Prerequisites for Implementation
Before you start ripping out your old secrets, check that your environment is ready to handle this:
- AKS Cluster: You need version 1.22 or higher.
- Azure CLI: Version 2.47 or higher.
- Permissions: You’ll need
ContributororUser Access Administratorrights on the resource group to set up the identities and federated credentials.
Double-check the Microsoft Official Documentation to make sure your cluster configuration is up to snuff before you dive in.
Enabling Workload Identity on AKS
First, you need to turn on the OIDC issuer. This allows your cluster to act as an identity provider.
# Enable the OIDC issuer and Workload Identity add-on
az aks update -g <resource-group> -n <cluster-name> --enable-oidc-issuer --enable-workload-identity
Once that’s done, grab the OIDC issuer URL. You’ll need it for the federation step.
az aks show -g <resource-group> -n <cluster-name> --query "oidcIssuerProfile.issuerUrl" -o tsv
Provisioning the Managed Identity
Ditch the Service Principal. We’re using a User-Assigned Managed Identity now. Create it in the same region as your cluster:
az identity create --name <identity-name> --resource-group <resource-group>
Now, assign the roles. Keep it tight. Don't just throw Contributor at it unless you have to. If your pod only needs to read from a Blob Storage container, give it Storage Blob Data Reader and nothing else. That’s the principle of least privilege in action.
Establishing the Federated Identity Credential
This is the "magic link." You are explicitly telling Entra ID that a specific Kubernetes Service Account in a specific namespace has the green light to assume the Managed Identity.
az identity federated-credential create \
--name <credential-name> \
--identity-name <identity-name> \
--resource-group <resource-group> \
--issuer <oidc-issuer-url> \
--subject system:serviceaccount:<namespace>:<service-account-name>
Just swap out those <namespace> and <service-account-name> placeholders with the ones you’re actually using.
Annotating Your Deployments
Your manifests need a little nudge to trigger the identity injection. Add the azure.workload.identity/use: "true" label to your pod template and make sure the serviceAccountName matches your federation settings.
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
azure.workload.identity/client-id: <client-id-of-managed-identity>
name: <service-account-name>
namespace: <namespace>
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
metadata:
labels:
azure.workload.identity/use: "true"
spec:
serviceAccountName: <service-account-name>
containers:
- name: my-app
image: my-app-image
When your pod spins up, the mutating admission controller takes over. It automatically injects the environment variables and mounts the token path. You don't have to lift a finger.
Development Workflow: Using the Azure Identity SDK
Here’s the best part: your code doesn’t have to change. By using the DefaultAzureCredential class from the Azure Identity Client Libraries, your app automatically picks up the credentials from the environment when it's running in AKS.
When you’re debugging on your local machine, DefaultAzureCredential is smart enough to fall back to your Azure CLI login. It’s a seamless dev experience. No more weird local identity hacks.
Verification and Troubleshooting
If your pod starts but can’t authenticate, don’t panic. First, check if the injection actually happened. Exec into your pod and look for the AZURE_FEDERATED_TOKEN_FILE environment variable:
kubectl exec -it <pod-name> -- env | grep AZURE
Missing variables? Your annotation is probably wrong, or the admission controller isn't running. Getting a 401 Unauthorized? Double-check that the client-id annotation on your Service Account actually matches the Client ID of your Managed Identity. For the deeper, weirder issues, check the AKS Workload Identity GitHub Repo.
Beyond the Basics: Governance and Compliance
Moving to Workload Identity makes auditing a breeze. Since every request to Azure is tied to a specific Managed Identity, you can use Azure Monitor and Log Analytics to see exactly which pods are hitting which resources. It’s a cornerstone of solid identity governance strategies. You can finally spot over-privileged identities and prune them before they become a liability.
Frequently Asked Questions
What is the difference between Managed Identity and Workload Identity?
Managed Identity is the broad Azure feature that lets resources like VMs or Functions talk to other Azure services. Workload Identity is the specific implementation for Kubernetes. It lets your AKS pods assume that identity without you having to stuff any secrets into the cluster.
Do I need to rotate keys with Workload Identity?
No. That’s the biggest win. Because you’re using OIDC federation and short-lived tokens, there are no long-lived client secrets to rotate. You kill the risk of leakage and end the headache of manual rotation cycles.
Can I use Workload Identity if my cluster is not on Azure?
Yes. Using Azure Arc-enabled Kubernetes, you can extend Workload Identity to clusters running on-premises or in other clouds. You’ll need to register the cluster with Azure Arc and install the extensions, but the application side remains mostly the same.
How do I troubleshoot "401 Unauthorized" errors with Workload Identity?
First, verify your OIDC issuer URL is correct. Second, check that the federated identity credential actually exists and that the "Subject" field matches your Service Account name and namespace perfectly. Finally, make sure the azure.workload.identity/client-id annotation on your Service Account matches the Managed Identity client ID.
Is Workload Identity compatible with all Azure SDKs?
Yes, as long as you’re using modern versions of the Azure Identity libraries. They support the OIDC token exchange out of the box. If you’re stuck on ancient SDK versions, you’ll need to upgrade to handle the identity tokens correctly.