Tutorial: Use a workload identity with an application on Azure Kubernetes Service (AKS)
Azure Kubernetes Service (AKS) is a managed Kubernetes service that lets you quickly deploy and manage Kubernetes clusters. In this tutorial, you:
- Deploy an AKS cluster using the Azure CLI with OpenID Connect (OIDC) Issuer and managed identity.
- Create an Azure Key Vault and secret.
- Create an Azure Active Directory (Azure AD) workload identity and Kubernetes service account.
- Configure the managed identity for token federation.
- Deploy the workload and verify authentication with the workload identity.
Before you begin
- This tutorial assumes a basic understanding of Kubernetes concepts. For more information, see Kubernetes core concepts for Azure Kubernetes Service (AKS).
- If you aren't familiar with Azure AD workload identity, see the Azure AD workload identity overview.
- When you create an AKS cluster, a second resource group is automatically created to store the AKS resources. For more information, see Why are two resource groups created with AKS?
Prerequisites
- If you don't have an Azure subscription, create an Azure free account before you begin.
- This article requires version 2.47.0 or later of the Azure CLI. If using Azure Cloud Shell, the latest version is already installed.
- The identity you use to create your cluster must have the appropriate minimum permissions. For more information on access and identity for AKS, see Access and identity options for Azure Kubernetes Service (AKS).
- If you have multiple Azure subscriptions, select the appropriate subscription ID in which the resources should be billed using the
az account
command.
Create a resource group
An Azure resource group is a logical group in which Azure resources are deployed and managed. When you create a resource group, you're prompted to specify a location. This location is the storage location of your resource group metadata and where your resources run in Azure if you don't specify another region during resource creation.
The following example creates a resource group named myResourceGroup in the eastus location.
Create a resource group using the
az group create
command.az group create --name myResourceGroup --location eastus
The following output example resembles successful creation of the resource group:
{ "id": "/subscriptions/<guid>/resourceGroups/myResourceGroup", "location": "eastus", "managedBy": null, "name": "myResourceGroup", "properties": { "provisioningState": "Succeeded" }, "tags": null }
Export environmental variables
To help simplify steps to configure the identities required, the steps below define environmental variables for reference on the cluster.
Create these variables using the following commands. Replace the default values for
RESOURCE_GROUP
,LOCATION
,SERVICE_ACCOUNT_NAME
,SUBSCRIPTION
,USER_ASSIGNED_IDENTITY_NAME
, andFEDERATED_IDENTITY_CREDENTIAL_NAME
.export RESOURCE_GROUP="myResourceGroup" export LOCATION="westcentralus" export SERVICE_ACCOUNT_NAMESPACE="default" export SERVICE_ACCOUNT_NAME="workload-identity-sa" export SUBSCRIPTION="$(az account show --query id --output tsv)" export USER_ASSIGNED_IDENTITY_NAME="myIdentity" export FEDERATED_IDENTITY_CREDENTIAL_NAME="myFedIdentity" export KEYVAULT_NAME="azwi-kv-tutorial" export KEYVAULT_SECRET_NAME="my-secret"
Create an AKS cluster
Create an AKS cluster using the
az aks create
command with the--enable-oidc-issuer
parameter to use the OIDC Issuer.az aks create -g "${RESOURCE_GROUP}" -n myAKSCluster --node-count 1 --enable-oidc-issuer --enable-workload-identity --generate-ssh-keys
After a few minutes, the command completes and returns JSON-formatted information about the cluster.
Get the OIDC Issuer URL and save it to an environmental variable using the following command. Replace the default value for the arguments
-n
, which is the name of the cluster.export AKS_OIDC_ISSUER="$(az aks show -n myAKSCluster -g "${RESOURCE_GROUP}" --query "oidcIssuerProfile.issuerUrl" -otsv)"
Create an Azure Key Vault and secret
Create an Azure Key Vault in resource group you created in this tutorial using the
az keyvault create
command.az keyvault create --resource-group "${RESOURCE_GROUP}" --location "${LOCATION}" --name "${KEYVAULT_NAME}"
The output of this command shows properties of the newly created key vault. Take note of the two properties listed below:
Name
: The vault name you provided to the--name
parameter.vaultUri
: In the example, this ishttps://<your-unique-keyvault-name>.vault.azure.net/
. Applications that use your vault through its REST API must use this URI.
At this point, your Azure account is the only one authorized to perform any operations on this new vault.
Add a secret to the vault using the
az keyvault secret set
command. The password is the value you specified for the environment variableKEYVAULT_SECRET_NAME
and stores the value of Hello! in it.az keyvault secret set --vault-name "${KEYVAULT_NAME}" --name "${KEYVAULT_SECRET_NAME}" --value 'Hello!'
Add the Key Vault URL to the environment variable
KEYVAULT_URL
using theaz keyvault show
command.export KEYVAULT_URL="$(az keyvault show -g "${RESOURCE_GROUP}" -n ${KEYVAULT_NAME} --query properties.vaultUri -o tsv)"
Create a managed identity and grant permissions to access the secret
Set a specific subscription as the current active subscription using the
az account set
command.az account set --subscription "${SUBSCRIPTION}"
Create a managed identity using the
az identity create
command.az identity create --name "${USER_ASSIGNED_IDENTITY_NAME}" --resource-group "${RESOURCE_GROUP}" --location "${LOCATION}" --subscription "${SUBSCRIPTION}"
Set an access policy for the managed identity to access the Key Vault secret using the following commands.
export USER_ASSIGNED_CLIENT_ID="$(az identity show --resource-group "${RESOURCE_GROUP}" --name "${USER_ASSIGNED_IDENTITY_NAME}" --query 'clientId' -otsv)"
az keyvault set-policy --name "${KEYVAULT_NAME}" --secret-permissions get --spn "${USER_ASSIGNED_CLIENT_ID}"
Create Kubernetes service account
Create a Kubernetes service account and annotate it with the client ID of the managed identity created in the previous step using the
az aks get-credentials
command. Replace the default value for the cluster name and the resource group name.az aks get-credentials -n myAKSCluster -g "${RESOURCE_GROUP}"
Copy the following multi-line input into your terminal and run the command to create the service account.
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: annotations: azure.workload.identity/client-id: ${USER_ASSIGNED_CLIENT_ID} labels: azure.workload.identity/use: "true" name: ${SERVICE_ACCOUNT_NAME} namespace: ${SERVICE_ACCOUNT_NAMESPACE} EOF
The following output resembles successful creation of the identity:
Serviceaccount/workload-identity-sa created
Establish federated identity credential
Create the federated identity credential between the managed identity, service account issuer, and subject using the
az identity federated-credential create
command.az identity federated-credential create --name ${FEDERATED_IDENTITY_CREDENTIAL_NAME} --identity-name ${USER_ASSIGNED_IDENTITY_NAME} --resource-group ${RESOURCE_GROUP} --issuer ${AKS_OIDC_ISSUER} --subject system:serviceaccount:${SERVICE_ACCOUNT_NAMESPACE}:${SERVICE_ACCOUNT_NAME}
Note
It takes a few seconds for the federated identity credential to propagate after it's initially added. If a token request is immediately available after adding the federated identity credential, you may experience failure for a couple minutes, as the cache is populated in the directory with old data. To avoid this issue, you can add a slight delay after adding the federated identity credential.
Deploy the workload
Deploy a pod that references the service account created in the previous step using the following command.
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: quick-start namespace: ${SERVICE_ACCOUNT_NAMESPACE} labels: azure.workload.identity/use: "true" spec: serviceAccountName: ${SERVICE_ACCOUNT_NAME} containers: - image: ghcr.io/azure/azure-workload-identity/msal-go name: oidc env: - name: KEYVAULT_URL value: ${KEYVAULT_URL} - name: SECRET_NAME value: ${KEYVAULT_SECRET_NAME} nodeSelector: kubernetes.io/os: linux EOF
The following output resembles successful creation of the pod:
pod/quick-start created
Check whether all properties are injected properly with the webhook using the
kubectl describe
command.kubectl describe pod quick-start
Verify the pod can get a token and access the secret from the Key Vault using the
kubectl logs
command.kubectl logs quick-start
The following output resembles successful access of the token:
I1013 22:49:29.872708 1 main.go:30] "successfully got secret" secret="Hello!"
Clean up resources
You may wish to leave these resources in place. If you no longer need these resources, use the following commands to delete them.
Delete the pod using the
kubectl delete pod
command.kubectl delete pod quick-start
Delete the service account using the
kubectl delete sa
command.kubectl delete sa "${SERVICE_ACCOUNT_NAME}" --namespace "${SERVICE_ACCOUNT_NAMESPACE}"
Delete the Azure resource group and all its resources using the
az group delete
command.az group delete --name "${RESOURCE_GROUP}"
Next steps
In this tutorial, you deployed a Kubernetes cluster and deployed a simple container application to test working with an Azure AD workload identity.
This tutorial is for introductory purposes. For guidance on a creating full solutions with AKS for production, see AKS solution guidance.
Feedback
Submit and view feedback for