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.
When using Azure Container Registry (ACR) with Azure Kubernetes Service (AKS), you need to establish an authentication mechanism. You can configure the required permissions between ACR and AKS using the Azure CLI, Azure PowerShell, or Azure portal. This article provides examples to configure authentication between these Azure services using the Azure CLI or Azure PowerShell.
The AKS to ACR integration assigns the AcrPull role to the Microsoft Entra ID managed identity associated with the agent pool in your AKS cluster. For more information on AKS managed identities, see Summary of managed identities.
Important
There's a latency issue with Microsoft Entra groups when attaching ACR. If the AcrPull role is granted to a Microsoft Entra group and the kubelet identity is added to the group to complete the Azure role-based access control (Azure RBAC) configuration, there might be a delay before the RBAC group takes effect. If you're running automation that requires the Azure RBAC configuration to be complete, we recommend you use Bring your own kubelet identity as a workaround. You can precreate a user-assigned identity, add it to the Microsoft Entra group, then use the identity as the kubelet identity to create an AKS cluster. This method ensures the identity is added to the Microsoft Entra group before a token is generated by kubelet, which avoids the latency issue.
Note
This article covers automatic authentication between AKS and ACR. If you need to pull an image from a private external registry, use an image pull secret.
Caution
The AKS-ACR integration through az aks --attach-acr isn't supported for ABAC-enabled ACR registries where the role assignment permissions mode is set to "RBAC Registry + ABAC Repository Permissions." ABAC-enabled ACR registries require the Container Registry Repository Reader role instead of the AcrPull role for granting image pull permissions. For ABAC-enabled ACR registries, you shouldn't use az aks --attach-acr but instead manually assign the Container Registry Repository Reader role assignment using either the Azure portal, az role assignment CLI, or Azure Resource Manager. For more information on ABAC-enabled ACR registries, see Azure attribute-based access control.
In this walkthrough, you configure an Azure Kubernetes Service (AKS) cluster to securely pull images from an Azure Container Registry (ACR). In Azure CLI, use --attach-acr. In Terraform, assign the AcrPull role to the AKS kubelet managed identity. This guide follows the same flow as the Azure CLI workflow while using Terraform for infrastructure provisioning.
Before you begin
- You need the Owner, Azure account administrator, or Azure co-administrator role on your Azure subscription.
- To avoid the need for these roles, you can instead use an existing managed identity to authenticate ACR from AKS. For more information, see Use an Azure managed identity to authenticate to an ACR.
- If you're using Azure CLI, this article requires that you're running Azure CLI version 2.7.0 or later. to find the version, run the
az --versioncommand. If you need to install or upgrade, see Install Azure CLI.
- If you're using Azure PowerShell, this article requires that you're running Azure PowerShell version 5.9.0 or later. To find the version, run the
Get-InstalledModule -Name Azcommand. If you need to install or upgrade, see Install Azure PowerShell. - Examples and syntax to use Terraform for configuring ACR can be found in the Terraform reference.
- Terraform installed (
>= 1.6). - Azure CLI installed and signed in to your subscription.
- Permissions to assign roles (Owner or User Access Administrator).
In this article, you configure an Azure Kubernetes Service (AKS) cluster to securely pull images from an Azure Container Registry (ACR). In Azure CLI, use --attach-acr. In Terraform, assign the AcrPull role to the AKS kubelet managed identity.
This article follows the same flow as the Azure CLI workflow while using Terraform for infrastructure provisioning. To verify you're signed in to the correct subscription, use the following Azure CLI commands:
az login
az account show
Create a new ACR
If you don't already have an ACR, create one using the az acr create command.
The registry name must be globally unique within Azure, and contain 5-50 alphanumeric characters, excluding dash (-) characters. This name is part of the fully qualified DNS name of the registry.
export RANDOM_STRING=$(printf '%05d%05d' "$RANDOM" "$RANDOM")
export MYACR="mycontainerregistry$RANDOM_STRING"
export ACR_RESOURCE_GROUP="myContainerRegistryResourceGroup"
export LOCATION="westcentralus"
az group create \
--name $ACR_RESOURCE_GROUP \
--location $LOCATION
az acr create \
--name $MYACR \
--resource-group $ACR_RESOURCE_GROUP \
--sku basic
The RANDOM_STRING variable stores a random 10-digit string. The MYACR value is concatenated with the RANDOM_STRING value to create a unique name.
If you don't already have an ACR, create one using the New-AzContainerRegistry cmdlet.
The registry name must be globally unique within Azure, and contain 5-50 alphanumeric characters, excluding dash (-) characters. This name is part of the fully qualified DNS name of the registry.
$RandomString = (Get-Random -Minimum 1000000000 -Maximum 10000000000).ToString()
$MyAcr = "mycontainerregistry$RandomString"
$AcrResourceGroup = "myContainerRegistryResourceGroup"
$Location = "westcentralus"
New-AzResourceGroup -Name $AcrResourceGroup -Location $Location
$NewAcr = @{
Name = $MyAcr
ResourceGroupName = $AcrResourceGroup
Location = $Location
Sku = "Basic"
}
New-AzContainerRegistry @NewAcr
The $RandomString variable stores a random 10-digit string. The $MyAcr value is concatenated with the $RandomString value to create a unique name.
Create a main.tf file for the configuration, and begin by defining the Terraform providers and generating a unique suffix for globally unique resource names. A globally unique name ensures your Azure Container Registry name doesn't conflict with existing registries.
terraform {
required_version = ">= 1.6.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.6"
}
}
}
provider "azurerm" {
features {}
}
resource "random_string" "suffix" {
length = 6
upper = false
special = false
}
Create a new AKS cluster and integrate with an existing ACR
Create a new AKS cluster and integrate with an existing ACR using the az aks create command with the --attach-acr parameter. This command allows you to authorize an existing ACR in your subscription and configures the appropriate AcrPull role for the managed identity.
export CLUSTER_NAME="myAKSCluster"
export CLUSTER_RESOURCE_GROUP="myClusterResourceGroup"
az group create \
--name $CLUSTER_RESOURCE_GROUP \
--location $LOCATION
az aks create \
--name $CLUSTER_NAME \
--resource-group $CLUSTER_RESOURCE_GROUP \
--generate-ssh-keys \
--attach-acr $MYACR
Use an ACR in a different subscription or attach using resource ID
If you're using an ACR located in a different subscription from your AKS cluster or would prefer to use the ACR resource ID instead of the ACR name, use the following syntax. This example creates the ACR_RESOURCE_ID variable using the container registry created in the previous section.
ACR_RESOURCE_ID=$(az acr show \
--name $MYACR \
--resource-group $ACR_RESOURCE_GROUP \
--query id --output tsv)
az aks create \
--name $CLUSTER_NAME \
--resource-group $CLUSTER_RESOURCE_GROUP \
--generate-ssh-keys \
--attach-acr $ACR_RESOURCE_ID
Create a new AKS cluster and integrate with an existing ACR using the New-AzAksCluster cmdlet with the -AcrNameToAttach parameter. This command allows you to authorize an existing ACR in your subscription and configures the appropriate AcrPull role for the managed identity.
$ClusterName = "myAKSCluster"
$ClusterResourceGroup = "myClusterResourceGroup"
New-AzResourceGroup -Name $ClusterResourceGroup -Location $Location
$NewCluster = @{
Name = $ClusterName
ResourceGroupName = $ClusterResourceGroup
GenerateSshKey = $true
AcrNameToAttach = $MyAcr
}
New-AzAksCluster @NewCluster
Use an ACR in a different subscription or attach using resource ID
Azure PowerShell only supports attaching ACR to AKS using the -AcrNameToAttach parameter and doesn't support attaching to an ACR by resource ID.
Next, create a resource group and an Azure Container Registry. This registry stores the container images that your AKS cluster pulls later.
locals {
location = "westcentralus"
acr_name = "myacr${random_string.suffix.result}"
acr_resource_group = "myContainerRegistryResourceGroup"
}
resource "azurerm_resource_group" "acr_rg" {
name = local.acr_resource_group
location = local.location
}
resource "azurerm_container_registry" "acr" {
name = local.acr_name
resource_group_name = azurerm_resource_group.acr_rg.name
location = azurerm_resource_group.acr_rg.location
sku = "Basic"
admin_enabled = false
}
Now create the AKS cluster that consumes images from the registry. This cluster uses a system-assigned managed identity, which will be granted permission to pull images.
locals {
aks_name = "myAKSCluster"
aks_resource_group = "myClusterResourceGroup"
}
resource "azurerm_resource_group" "aks_rg" {
name = local.aks_resource_group
location = local.location
}
resource "azurerm_kubernetes_cluster" "aks" {
name = local.aks_name
location = azurerm_resource_group.aks_rg.location
resource_group_name = azurerm_resource_group.aks_rg.name
dns_prefix = local.aks_name
identity {
type = "SystemAssigned"
}
default_node_pool {
name = "systempool"
node_count = 2
vm_size = "Standard_DS2_v2"
}
}
At this stage, the AKS cluster exists, but it doesn't yet have access to the container registry. In Azure CLI, use the --attach-acr parameter. In Terraform, you explicitly assign the AcrPull role.
resource "azurerm_role_assignment" "aks_acr_pull" {
scope = azurerm_container_registry.acr.id
role_definition_name = "AcrPull"
principal_id = azurerm_kubernetes_cluster.aks.kubelet_identity[0].object_id
}
Configure ACR integration for an existing AKS cluster
You can attach an ACR to an existing AKS cluster, or detach an ACR from an AKS cluster if you no longer want the cluster to have access to the registry.
The previous examples in the article created an Azure Container Registry and an Azure Kubernetes Service cluster attached to the ACR. The following are examples of how to attach or detach a container registry from a cluster and use the ACR and AKS cluster created in this article. You can replace the variable values with your own ACR and AKS cluster values.
Attach an ACR to an existing AKS cluster
Integrate an existing ACR with an existing AKS cluster using the az aks update command with the --attach-acr parameter.
# Attach using acr-name
az aks update \
--name $CLUSTER_NAME \
--resource-group $CLUSTER_RESOURCE_GROUP \
--attach-acr $MYACR
# Attach using acr-resource-id
az aks update \
--name $CLUSTER_NAME \
--resource-group $CLUSTER_RESOURCE_GROUP \
--attach-acr $ACR_RESOURCE_ID
The az aks update --attach-acr command uses the permissions of the user running the command to create the ACR role assignment. This role is assigned to the kubelet managed identity. For more information on AKS managed identities, see Summary of managed identities.
Integrate an existing ACR with an existing AKS cluster using the Set-AzAksCluster command with the -AcrNameToAttach parameter.
$AttachCluster = @{
Name = $ClusterName
ResourceGroupName = $ClusterResourceGroup
AcrNameToAttach = $MyAcr
}
Set-AzAksCluster @AttachCluster
The Set-AzAksCluster -AcrNameToAttach cmdlet uses the permissions of the user running the command to create the role ACR assignment. This role is assigned to the kubelet managed identity. For more information on AKS managed identities, see Summary of managed identities.
If your AKS cluster already exists, you can attach an ACR by referencing both resources and creating the same role assignment.
data "azurerm_kubernetes_cluster" "existing_aks" {
name = "myAKSCluster"
resource_group_name = "myClusterResourceGroup"
}
data "azurerm_container_registry" "existing_acr" {
name = "mycontainerregistry"
resource_group_name = "myContainerRegistryResourceGroup"
}
resource "azurerm_role_assignment" "existing_aks_acr_pull" {
scope = data.azurerm_container_registry.existing_acr.id
role_definition_name = "AcrPull"
principal_id = data.azurerm_kubernetes_cluster.existing_aks.kubelet_identity[0].object_id
}
Detach an ACR from an AKS cluster
Remove the integration between an ACR and an AKS cluster using the az aks update command with the --detach-acr parameter.
# Detach using acr-name
az aks update \
--name $CLUSTER_NAME \
--resource-group $CLUSTER_RESOURCE_GROUP \
--detach-acr $MYACR
# Detach using acr-resource-id
az aks update \
--name $CLUSTER_NAME \
--resource-group $CLUSTER_RESOURCE_GROUP \
--detach-acr $ACR_RESOURCE_ID
Remove the integration between an ACR and an AKS cluster using the Set-AzAksCluster command with the -AcrNameToDetach parameter.
$DetachCluster = @{
Name = $ClusterName
ResourceGroupName = $ClusterResourceGroup
AcrNameToDetach = $MyAcr
}
Set-AzAksCluster @DetachCluster
To remove access, delete the role assignment that grants the cluster permission to pull images.
# Remove this resource to revoke access
# resource "azurerm_role_assignment" "existing_aks_acr_pull" {
# scope = data.azurerm_container_registry.existing_acr.id
# role_definition_name = "AcrPull"
# principal_id = data.azurerm_kubernetes_cluster.existing_aks.kubelet_identity[0].object_id
# }
Initialize and deploy the configuration
After your configuration is complete, initialize Terraform and review the execution plan before applying.
terraform fmt
terraform init
terraform validate
terraform plan
terraform apply
At this point, your AKS cluster is configured to pull images from ACR.
You can now:
- Import images into ACR.
- Deploy workloads to AKS.
- Verify pod deployment.
Working with ACR and AKS
Import an image into your ACR, then deploy that image to your AKS cluster.
Import an image into your ACR
Import an image from Docker Hub into your ACR using the az acr import command.
az acr import \
--name $MYACR \
--source docker.io/library/nginx:latest \
--image nginx:v1
Run the following commands to verify the image was imported.
az acr repository show --name $MYACR --repository nginx
az acr repository show-tags --name $MYACR --repository nginx
Import an image from Docker Hub into your ACR using the Import-AzContainerRegistryImage cmdlet.
$ImportImage = @{
RegistryName = $MyAcr
ResourceGroupName = $AcrResourceGroup
SourceRegistryUri = 'docker.io'
SourceImage = 'library/nginx:latest'
TargetTag = 'nginx:v1'
}
Import-AzContainerRegistryImage @ImportImage
Run the following commands to verify the image was imported.
Get-AzContainerRegistryRepository -RegistryName $MyAcr
Get-AzContainerRegistryTag -RegistryName $MyAcr -Repository nginx
Create deployment file
Create a Kubernetes deployment that references the image you imported into ACR. If the deployment is successful and the image is pulled correctly, your AKS cluster is properly integrated with ACR.
Create a file named acr-nginx.yaml using the following sample YAML. In the image property, replace acr-name with the name of your ACR. In Azure CLI, run echo $MYACR to display the ACR name. In Azure PowerShell, run $MyAcr to display the ACR name.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx0-deployment
labels:
app: nginx0-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx0
template:
metadata:
labels:
app: nginx0
spec:
containers:
- name: nginx
image: <acr-name>.azurecr.io/nginx:v1
ports:
- containerPort: 80
Get credentials and run deployment
Ensure you have the proper AKS credentials using the
az aks get-credentialscommand.az aks get-credentials \ --resource-group $CLUSTER_RESOURCE_GROUP \ --name $CLUSTER_NAMERun the deployment in your AKS cluster using the
kubectl applycommand.kubectl apply -f acr-nginx.yamlMonitor the deployment using the
kubectl get podscommand.kubectl get podsThe output should show two running pods, as shown in the following example output:
NAME READY STATUS RESTARTS AGE nginx0-deployment-669dfc4d4b-x74kr 1/1 Running 0 20s nginx0-deployment-669dfc4d4b-xdpd6 1/1 Running 0 20s
Ensure you have the proper AKS credentials using the
Import-AzAksCredentialcmdlet.Import-AzAksCredential -ResourceGroupName $ClusterResourceGroup -Name $ClusterNameRun the deployment in your AKS cluster using the
kubectl applycommand.kubectl apply -f acr-nginx.yamlMonitor the deployment using the
kubectl get podscommand.kubectl get podsThe output should show two running pods, as shown in the following example output:
NAME READY STATUS RESTARTS AGE nginx0-deployment-669dfc4d4b-x74kr 1/1 Running 0 20s nginx0-deployment-669dfc4d4b-xdpd6 1/1 Running 0 20s
Troubleshooting
- Validate the registry is accessible from the AKS cluster using the
az aks check-acrcommand. - If your AKS cluster uses an HTTP proxy and your ACR uses Private Link, add both ACR endpoints (REST and data) to the cluster
noProxylist. For more information, see HTTP proxy support in Azure Kubernetes Service (AKS). - Learn more about ACR monitoring.
- Learn more about ACR health.
Clean up resources
When you no longer need the resources created in this article, you can delete the resource groups to remove all associated resources. These commands delete the ACR and AKS cluster and the clusters node resource group that begins with MC_.
az group delete --name $ACR_RESOURCE_GROUP --yes --no-wait
az group delete --name $CLUSTER_RESOURCE_GROUP --yes --no-wait
Remove-AzResourceGroup -Name $AcrResourceGroup -Force
Remove-AzResourceGroup -Name $ClusterResourceGroup -Force