This guide demonstrates how to access Azure Key Vault secrets from a Python app running in AKS, using Microsoft Entra Workload Identity for secure identity federation.
- Uses Microsoft Entra Workload Identity
- Pod assumes identity securely without needing node identity
- Access Azure Key Vault using
DefaultAzureCredential - Least-privilege RBAC using federated credentials
- Azure CLI (2.45.0+)
kubectl- OIDC-enabled AKS cluster
- Azure subscription with Owner/Contributor rights
cat <<EOF > env.sh
export LOCATION="southeastasia"
export RESOURCE_GROUP="aks-wi-demo-rg"
export AKS_NAME="akswi$(openssl rand -hex 3 | tr -dc 'a-z0-9' | cut -c1-10)"
export KEYVAULT_NAME="kvwi$(openssl rand -hex 3 | tr -dc 'a-z0-9' | cut -c1-20)"
export SECRET_NAME="DemoSecret"
export SECRET_VALUE="SuperSecret123"
export APP_NAME="kv-reader"
export IMAGE_NAME="kv-reader"
export ACR_NAME="acrwi$(openssl rand -hex 3 | tr -dc 'a-z0-9' | cut -c1-20)"
export IDENTITY_NAME="uami-kv-access"
export SERVICE_ACCOUNT_NAME="workload-identity-sa"
export NAMESPACE="default"
EOF
source env.shaz group create --name $RESOURCE_GROUP --location $LOCATION
az aks create \
--name $AKS_NAME \
--resource-group $RESOURCE_GROUP \
--enable-oidc-issuer \
--enable-workload-identity \
--node-count 1 \
--generate-ssh-keys
az aks get-credentials --name $AKS_NAME --resource-group $RESOURCE_GROUPaz keyvault create \
--name $KEYVAULT_NAME \
--resource-group $RESOURCE_GROUP \
--location $LOCATION \
--enable-rbac-authorization true
az keyvault secret set \
--vault-name $KEYVAULT_NAME \
--name $SECRET_NAME \
--value "$SECRET_VALUE"az identity create \
--name $IDENTITY_NAME \
--resource-group $RESOURCE_GROUP \
--location $LOCATIONStore client ID:
IDENTITY_CLIENT_ID=$(az identity show --name $IDENTITY_NAME --resource-group $RESOURCE_GROUP --query clientId -o tsv)IDENTITY_PRINCIPAL_ID=$(az identity show --name $IDENTITY_NAME --resource-group $RESOURCE_GROUP --query principalId -o tsv)
az role assignment create \
--assignee-object-id $IDENTITY_PRINCIPAL_ID \
--role "Key Vault Secrets User" \
--scope $(az keyvault show --name $KEYVAULT_NAME --query id -o tsv)AKS_OIDC_ISSUER=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query "oidcIssuerProfile.issuerUrl" -o tsv)
az identity federated-credential create \
--name federated-cred \
--identity-name $IDENTITY_NAME \
--resource-group $RESOURCE_GROUP \
--issuer $AKS_OIDC_ISSUER \
--subject "system:serviceaccount:$NAMESPACE:$SERVICE_ACCOUNT_NAME" \
--audiences api://AzureADTokenExchangefrom azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
import os
import time
vault_name = os.getenv("KEY_VAULT_NAME")
secret_name = os.getenv("SECRET_NAME")
vault_url = f"https://{vault_name}.vault.azure.net"
credential = DefaultAzureCredential()
client = SecretClient(vault_url=vault_url, credential=credential)
retrieved = client.get_secret(secret_name)
print(f"Secret value: {retrieved.value}")
# Wait indefinitely
print("App is running. Press Ctrl+C to exit.")
while True:
time.sleep(60)FROM python:3.10-slim
WORKDIR /app
COPY app.py .
RUN pip install azure-identity azure-keyvault-secrets
CMD ["python", "app.py"]az acr create --resource-group $RESOURCE_GROUP --name $ACR_NAME --sku Basic
az aks update -n $AKS_NAME -g $RESOURCE_GROUP --attach-acr $ACR_NAME
az acr login --name $ACR_NAME
docker build -t $ACR_NAME.azurecr.io/$IMAGE_NAME:v1 .
docker push $ACR_NAME.azurecr.io/$IMAGE_NAME:v1apiVersion: v1
kind: ServiceAccount
metadata:
name: $SERVICE_ACCOUNT_NAME
annotations:
azure.workload.identity/client-id: "$IDENTITY_CLIENT_ID"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kv-reader
spec:
replicas: 1
selector:
matchLabels:
app: kv-reader
template:
metadata:
labels:
app: kv-reader
spec:
serviceAccountName: $SERVICE_ACCOUNT_NAME
containers:
- name: kv-reader
image: $ACR_NAME.azurecr.io/$IMAGE_NAME:v1
env:
- name: KEY_VAULT_NAME
value: "$KEYVAULT_NAME"
- name: SECRET_NAME
value: "$SECRET_NAME"Apply it:
envsubst < deployment.yaml | kubectl apply -f -kubectl get pods
kubectl logs $(kubectl get pods -l app=kv-reader -o jsonpath="{.items[0].metadata.name}")Expected output:
Secret value: SuperSecret123
az group delete --name $RESOURCE_GROUP --yes --no-waitYou have now successfully set up AKS to access Azure Key Vault using Microsoft Entra Workload Identity.