Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Azure Workload Identity enables your pods to authenticate to Azure services by using short-lived, automatically rotated federation tokens instead of stored credentials. This approach means you don't need to manually rotate secrets, and it reduces the risk of credential leaks.
Azure Red Hat OpenShift with hosted control planes clusters deploy the azure-workload-identity-webhook webhook (MutatingWebhookConfiguration) by default. When you annotate a service account and label your pods, the webhook automatically injects the federation tokens and environment variables your application needs to authenticate.
Prepare your environment
Set the required environment variables and verify that your cluster’s OIDC configuration and workload identity webhook are in place before creating Azure identity resources.
Set the OIDC issuer URL.
The OIDC issuer URL is used to verify that a token presented by a pod actually came from the expected OpenShift cluster, completing the trust chain between a Kubernetes service account and an Azure managed identity without any shared secrets.
OIDC_ISSUER=$(oc get authentication.config.openshift.io/cluster -o jsonpath='{.spec.serviceAccountIssuer}')Verify the OIDC issuer URL.
echo $OIDC_ISSUERExample output:
https://<region>.oic.aro-hcp.azure.com/<tenant-id>/<cluster-id>Set the Azure tenant and subscription IDs.
TENANT_ID=$(az account show --query tenantId -o tsv) SUBSCRIPTION_ID=$(az account show --query id -o tsv) RESOURCE_GROUP="my-resource-group"Verify the OIDC discovery endpoint.
oc get --raw /.well-known/openid-configuration | jq .Confirm that the issuer field matches
OIDC_ISSUER, and that thejwks_uriis reachable.Confirm the webhook is running.
oc get mutatingwebhookconfigurations azure-workload-identity-webhook -o yaml | grep -E 'name:|namespaceSelector|failurePolicy'
Example output:
name: azure-workload-identity-webhook
failurePolicy: Fail
name: pod-identity-webhook.azure.mutate.io
namespaceSelector: {}
Create Azure identity resources
Create the Azure resources that link your Kubernetes service account to an Azure identity: a user-assigned managed identity, a role assignment that grants it permissions, and a federated credential that establishes trust with your cluster’s OIDC issuer.
Create a user-assigned managed identity.
IDENTITY_NAME="test-identity" az identity create --name "${IDENTITY_NAME}" \ --resource-group "${RESOURCE_GROUP}" \ --location "$(az group show --name ${RESOURCE_GROUP} --query location -o tsv)" MSI_CLIENT_ID=$(az identity show --name "${IDENTITY_NAME}" \ --resource-group "${RESOURCE_GROUP}" \ --query clientId -o tsv)Assign the required Azure role to the managed identity.
The role you assign depends on the Azure resources your application needs to access.
The following example assigns the Reader role scoped to a resource group:
MSI_OBJECT_ID=$(az identity show --name "${IDENTITY_NAME}" \ -resource-group "${RESOURCE_GROUP}" \ --query principalId -o tsv) az role assignment create --assignee-object-id "${MSI_OBJECT_ID}" \ --assignee-principal-type ServicePrincipal \ --role "Reader" \ --scope "/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}"Create a federated identity credential.
The federated identity credential links a Kubernetes service account to the Azure managed identity. The
--audiencesvalue must match the audience that the webhook injects (default:api://AzureADTokenExchange).TEST_NAMESPACE="wi-test" TEST_SERVICE_ACCOUNT="wi-test-sa" az identity federated-credential create \ --name "aro-hcp-${TEST_NAMESPACE}-${TEST_SERVICE_ACCOUNT}" \ --identity-name "${IDENTITY_NAME}" \ --resource-group "${RESOURCE_GROUP}" \ --issuer "${OIDC_ISSUER}" \ --subject "system:serviceaccount:${TEST_NAMESPACE}:${TEST_SERVICE_ACCOUNT}" \ --audiences "api://AzureADTokenExchange"Display the federated credential and verify that the
issuer,subject, andaudiencesfields match the values you specified.az identity federated-credential show --name "aro-hcp-${TEST_NAMESPACE}-${TEST_SERVICE_ACCOUNT}" \ --identity-name "${IDENTITY_NAME}" \ --resource-group "${RESOURCE_GROUP}"
Deploy an application with workload identity
Create the Kubernetes resources your application needs to use workload identity: a labeled service account that triggers the webhook, and a pod that uses that service account.
Create a namespace and an annotated service account.
The
azure.workload.identity/use: "true"label on the service account triggers the webhook to mutate pods that use this service account. Without this label, the webhook ignores the pod.oc create namespace "${TEST_NAMESPACE}" 2>/dev/null || true cat <<EOF | oc apply -f - piVersion: v1 kind: ServiceAccount metadata: name: ${TEST_SERVICE_ACCOUNT} namespace: ${TEST_NAMESPACE} annotations: azure.workload.identity/client-id: "${MSI_CLIENT_ID}" azure.workload.identity/tenant-id: "${TENANT_ID}" labels: azure.workload.identity/use: "true" EOFDeploy a pod that uses the annotated service account.
The pod must also have the
azure.workload.identity/use: "true"label.cat <<EOF | oc apply -f - apiVersion: v1 kind: Pod metadata: name: wi-test-pod namespace: ${TEST_NAMESPACE} labels: azure.workload.identity/use: "true" spec: serviceAccountName: ${TEST_SERVICE_ACCOUNT} containers: - name: azure-cli image: mcr.microsoft.com/azure-cli:latest command: ["sleep", "3600"] resources: requests: cpu: 100m memory: 128Mi limits: cpu: 200m memory: 256Mi restartPolicy: Never EOFWait for the pod to be ready.
oc wait --for=condition=Ready pod/wi-test-pod -n "${TEST_NAMESPACE}" \ --timeout=120s
Verify webhook injection
Confirm that the workload identity webhook correctly mutates your pod by checking that the expected environment variables, projected token volume, and token file are present.
Check the injected environment variables.
oc describe pod wi-test-pod -n "${TEST_NAMESPACE}" | \ grep -A1 -E "AZURE_|azure"The webhook injects the following environment variables:
Variable Expected value AZURE_CLIENT_IDThe client ID of your managed identity. AZURE_TENANT_IDYour Azure tenant ID. AZURE_FEDERATED_TOKEN_FILE/var/run/secrets/azure/tokens/azure-identity-tokenAZURE_AUTHORITY_HOSThttps://login.microsoftonline.com/- Verify that the audience for the projected token is
api://AzureADTokenExchange.
oc get pod wi-test-pod -n "${TEST_NAMESPACE}" -o json | \ jq '.spec.volumes[] | select(.name | contains("azure"))'Example output:
{ "name": "azure-identity-token", "projected": { "defaultMode": 420, "sources": [ { "serviceAccountToken": { "audience": "api://AzureADTokenExchange", "expirationSeconds": 3600, "path": "azure-identity-token" } } ] } }- Verify that the audience for the projected token is
Verify that the volume is mounted at
/var/run/secrets/azure/tokens.oc get pod wi-test-pod -n "${TEST_NAMESPACE}" -o json | \ jq '.spec.containers[0].volumeMounts[] | select(.mountPath | contains("azure"))'Example output:
{ "mountPath": "/var/run/secrets/azure/tokens", "name": "azure-identity-token", "readOnly": true }Verify the token file exists inside the pod.
oc exec -n "${TEST_NAMESPACE}" wi-test-pod \ -- ls -la /var/run/secrets/azure/tokens/The output should list the
azure-identity-tokenfile.
Verify Azure authentication
Test that the injected workload identity credentials can successfully authenticate to Azure services, using both the Azure CLI and the Azure SDK.
Verify Azure authentication by using the Azure CLI
Use the Azure CLI inside the pod to verify that the workload identity credentials are valid end-to-end. This step confirms that the injected environment variables and federated token can successfully authenticate to Azure and access resources.
Start an interactive shell on the
wi-test-pod.oc exec -it -n "${TEST_NAMESPACE}" wi-test-pod -- bashLog in by using workload identity. The webhook already sets all required environment variables.
az login --federated-token "$(cat $AZURE_FEDERATED_TOKEN_FILE)" \ --service-principal \ -u "$AZURE_CLIENT_ID" \ -t "$AZURE_TENANT_ID"Verify the authentication.
az account showTest an Azure API call.
az group show --name "<resource-group-name>"If the authentication succeeds and the API call returns results, workload identity is fully functional.
Verify Azure authentication by using the Azure SDK
Deploy a Python pod to verify that applications using the Azure SDK can authenticate automatically through workload identity. This procedure validates the programmatic authentication path that your real applications use. The DefaultAzureCredential class discovers the injected credentials without any explicit configuration, confirming that your workloads can authenticate to Azure services without code changes.
Deploy a Python pod.
cat <<'PYEOF' | oc apply -f - apiVersion: v1 kind: Pod metadata: name: wi-test-sdk namespace: wi-test labels: azure.workload.identity/use: "true" spec: serviceAccountName: wi-test-sa containers: - name: python image: python:3.11-slim command: - bash - -c - | pip install azure-identity azure-mgmt-resource -q python3 -c " from azure.identity import DefaultAzureCredential from azure.mgmt.resource import ResourceManagementClient import os credential = DefaultAzureCredential() token = credential.get_token('https://management.azure.com/.default') print(f'Token acquired! Expires: {token.expires_on}') print('SUCCESS: Workload Identity is fully functional!') " env: - name: AZURE_SUBSCRIPTION_ID value: "<SUBSCRIPTION_ID>" restartPolicy: Never PYEOFWait for the pod to be ready.
oc wait --for=condition=Ready pod/wi-test-sdk -n wi-test --timeout=180s || trueGet the logs for the pod.
oc logs wi-test-sdk -n wi-testExample output:
Token acquired! Expires: 1774644054 SUCCESS: Workload Identity is fully functional!