Configure cross-tenant workload identity on Azure Kubernetes Service (AKS)
In this article, you learn how to configure cross-tenant workload identity on Azure Kubernetes Service (AKS). Cross-tenant workload identity allows you to access resources in another tenant from your AKS cluster. In this example, you create an Azure Service Bus in one tenant and send messages to it from a workload running in an AKS cluster in another tenant.
For more information on workload identity, see the Workload identity overview.
Prerequisites
Two Azure subscriptions, each in a separate tenant. In this article, we refer to these as Tenant A and Tenant B.
Azure CLI installed on your local machine. If you don't have the Azure CLI installed, see Install the Azure CLI.
Bash shell environment. This article uses Bash shell syntax.
You need to have the following subscription details:
- Tenant A tenant ID
- Tenant A subscription ID
- Tenant B tenant ID
- Tenant B subscription ID
Important
Make sure you stay within the same terminal window for the duration of this article to retain the environment variables you set. If you close the terminal window, you need to set the environment variables again.
Configure resources in Tenant A
In Tenant A, you create an AKS cluster with workload identity and OIDC issuer enabled. You use this cluster to deploy an application that attempts to access resources in Tenant B.
Log in to Tenant A
Log in to your Tenant A subscription using the
az login
command.# Set environment variable TENANT_A_ID=<tenant-id> az login --tenant $TENANT_A_ID
Ensure you're working with the correct subscription in Tenant A using the
az account set
command.# Set environment variable TENANT_A_SUBSCRIPTION_ID=<subscription-id> # Log in to your Tenant A subscription az account set --subscription $TENANT_A_SUBSCRIPTION_ID
Create resources in Tenant A
Create a resource group in Tenant A to host the AKS cluster using the
az group create
command.# Set environment variables RESOURCE_GROUP=<resource-group-name> LOCATION=<location> # Create a resource group az group create --name $RESOURCE_GROUP --location $LOCATION
Create an AKS cluster in Tenant A with workload identity and OIDC issuer enabled using the
az aks create
command.# Set environment variable CLUSTER_NAME=<cluster-name> # Create an AKS cluster az aks create \ --resource-group $RESOURCE_GROUP \ --name $CLUSTER_NAME \ --enable-oidc-issuer \ --enable-workload-identity \ --generate-ssh-keys
Get OIDC issuer URL from AKS cluster
Get the OIDC issuer URL from the cluster in Tenant A using the
az aks show
command.OIDC_ISSUER_URL=$(az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --query "oidcIssuerProfile.issuerUrl" --output tsv)
Configure resources in Tenant B
In Tenant B, you create an Azure Service Bus, a managed identity and assign it permissions to read and write messages to the service bus, and establish the trust between the managed identity and the AKS cluster in Tenant A.
Log in to Tenant B
Log out of your Tenant A subscription using the
az logout
command.az logout
Log in to your Tenant B subscription using the
az login
command.# Set environment variable TENANT_B_ID=<tenant-id> az login --tenant $TENANT_B_ID
Ensure you're working with the correct subscription in Tenant B using the
az account set
command.# Set environment variable TENANT_B_SUBSCRIPTION_ID=<subscription-id> # Log in to your Tenant B subscription az account set --subscription $TENANT_B_SUBSCRIPTION_ID
Create resources in Tenant B
Create a resource group in Tenant B to host the managed identity using the
az group create
command.# Set environment variables RESOURCE_GROUP=<resource-group-name> LOCATION=<location> # Create a resource group az group create --name $RESOURCE_GROUP --location $LOCATION
Create a service bus and queue in Tenant B using the
az servicebus namespace create
andaz servicebus queue create
commands.# Set environment variable SERVICEBUS_NAME=sb-crosstenantdemo-$RANDOM # Create a new service bus namespace and and return the service bus hostname SERVICEBUS_HOSTNAME=$(az servicebus namespace create \ --name $SERVICEBUS_NAME \ --resource-group $RESOURCE_GROUP \ --disable-local-auth \ --query serviceBusEndpoint \ --output tsv | sed -e 's/https:\/\///' -e 's/:443\///') # Create a new queue in the service bus namespace az servicebus queue create \ --name myqueue \ --namespace $SERVICEBUS_NAME \ --resource-group $RESOURCE_GROUP
Create a user-assigned managed identity in Tenant B using the
az identity create
command.# Set environment variable IDENTITY_NAME=${SERVICEBUS_NAME}-identity # Create a user-assigned managed identity az identity create --resource-group $RESOURCE_GROUP --name $IDENTITY_NAME
Get resource IDs and assign permissions in Tenant B
Get the principal ID of the managed identity in Tenant B using the
az identity show
command.# Get the user-assigned managed identity principalId PRINCIPAL_ID=$(az identity show \ --resource-group $RESOURCE_GROUP \ --name $IDENTITY_NAME \ --query principalId \ --output tsv)
Get the client ID of the managed identity in Tenant B using the
az identity show
command.CLIENT_ID=$(az identity show \ --resource-group $RESOURCE_GROUP \ --name $IDENTITY_NAME \ --query clientId \ --output tsv)
Get the resource ID of the service bus namespace in Tenant B using the
az servicebus namespace show
command.SERVICEBUS_ID=$(az servicebus namespace show \ --name $SERVICEBUS_NAME \ --resource-group $RESOURCE_GROUP \ --query id \ --output tsv)
Assign the managed identity in Tenant B permissions to read and write service bus messages using the
az role assignment create
command.az role assignment create \ --role "Azure Service Bus Data Owner" \ --assignee-object-id $PRINCIPAL_ID \ --assignee-principal-type ServicePrincipal \ --scope $SERVICEBUS_ID
Establish trust between AKS cluster and managed identity
In this section, you create the federated identity credential needed to establish trust between the AKS cluster in Tenant A and the managed identity in Tenant B. You use the OIDC issuer URL from the AKS cluster in Tenant A and the name of the managed identity in Tenant B.
Create a federated identity credential using the
az identity federated-credential create
command.az identity federated-credential create \ --name $IDENTITY_NAME-$RANDOM \ --identity-name $IDENTITY_NAME \ --resource-group $RESOURCE_GROUP \ --issuer $OIDC_ISSUER_URL \ --subject system:serviceaccount:default:myserviceaccount
--subject system:serviceaccount:default:myserviceaccount
is the name of the Kubernetes service account that you create in Tenant A later in the article. When your application pod makes authentication requests, this value is sent to Microsoft Entra ID as the subject
in the authorization request. Microsoft Entra ID determines eligibility based on whether this value matches what you set when you created the federated identity credential, so it's important to ensure the value matches.
Deploy application to send messages to Azure Service Bus queue
In this section, you deploy an application to your AKS cluster in Tenant A that sends messages to the Azure Service Bus queue in Tenant B.
Log in to Tenant A and get AKS credentials
Log out of your Tenant B subscription using the
az logout
command.az logout
Log in to your Tenant A subscription using the
az login
command.az login --tenant $TENANT_A_ID
Ensure you're working with the correct subscription in Tenant A using the
az account set
command.az account set --subscription $TENANT_A_SUBSCRIPTION_ID
Get the credentials for the AKS cluster in Tenant A using the
az aks get-credentials
command.az aks get-credentials --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME
Create Kubernetes resources to send messages to Azure Service Bus queue
Create a new Kubernetes ServiceAccount in the
default
namespace and pass in the client ID of your managed identity in Tenant B to thekubectl apply
command. The client ID is used to authenticate the app in Tenant A to the Azure Service Bus in Tenant B.kubectl apply -f - <<EOF apiVersion: v1 kind: ServiceAccount metadata: annotations: azure.workload.identity/client-id: $CLIENT_ID name: myserviceaccount EOF
Create a new Kubernetes Job in the
default
namespace to send 100 messages to your Azure Service Bus queue. The Pod template is configured to use workload identity and the service account you created in the previous step. Also note that theAZURE_TENANT_ID
environment variable is set to the tenant ID of Tenant B. This is required as workload identity defaults to the tenant of the AKS cluster, so you need to explicitly set the tenant ID of Tenant B.kubectl apply -f - <<EOF apiVersion: batch/v1 kind: Job metadata: name: myproducer spec: template: metadata: labels: azure.workload.identity/use: "true" spec: serviceAccountName: myserviceaccount containers: - image: ghcr.io/azure-samples/aks-app-samples/servicebusdemo:latest name: myproducer resources: {} env: - name: OPERATION_MODE value: "producer" - name: MESSAGE_COUNT value: "100" - name: AZURE_SERVICEBUS_QUEUE_NAME value: myqueue - name: AZURE_SERVICEBUS_HOSTNAME value: $SERVICEBUS_HOSTNAME - name: AZURE_TENANT_ID value: $TENANT_B_ID restartPolicy: Never EOF
Verify the deployment
Verify that the pod is correctly configured to interact with the Azure Service Bus queue in Tenant B by checking the status of the pod using the
kubectl describe pod
command.# Get the dynamically generated pod name POD_NAME=$(kubectl get po --selector job-name=myproducer -o jsonpath='{.items[0].metadata.name}') # Verify the tenant ID environment variable is set for Tenant B kubectl describe pod $POD_NAME | grep AZURE_TENANT_ID
Check the logs of the pod to see if the application was able to send messages across tenants using the
kubectl logs
command.kubectl logs $POD_NAME
Your output should look similar to the following example output:
... Adding message to batch: Hello World! Adding message to batch: Hello World! Adding message to batch: Hello World! Sent 100 messages
Note
As an extra verification step, you can go to the Azure portal and navigate to the Azure Service Bus queue in Tenant B to view the messages that were sent in the Service Bus Explorer.
Clean up resources
After you verify that the deployment is successful, you can clean up the resources to avoid incurring Azure costs.
Delete resources in Tenant A
Log in to your Tenant A subscription using the
az login
command.az login --tenant $TENANT_A_ID
Ensure you're working with the correct subscription in Tenant A using the
az account set
command.az account set --subscription $TENANT_A_SUBSCRIPTION_ID
Delete the Azure resource group and all resources in it using the
az group delete
command.az group delete --name $RESOURCE_GROUP --yes --no-wait
Delete resources in Tenant B
Log in to your Tenant B subscription using the
az login
command.az login --tenant $TENANT_B_ID
Ensure you're working with the correct subscription in Tenant B using the
az account set
command.az account set --subscription $TENANT_B_SUBSCRIPTION_ID
Delete the Azure resource group and all resources in it using the
az group delete
command.az group delete --name $RESOURCE_GROUP --yes --no-wait
Next steps
In this article, you learned how to configure cross-tenant workload identity on Azure Kubernetes Service (AKS). To learn more about workload identity, see the following articles: