I’m trying to deploy a multi-container setup on Azure App Service using images stored in an Azure Container Registry (ACR). Both my App Service and ACR are configured to use managed identity, and I have assigned the ACR Pull role to the App Service’s managed identity.
I have been able to connect to the registry using Azure CLI and I’ve been able to push images from my pipeline.
However, when the App Service tries to pull the images, I encounter the following error in the logs:
DockerApiException: Docker API responded with status code=InternalServerError, response={"message":"Head "https://<my-registry>.azurecr.io/v2/<image>/manifests/latest": unauthorized: authentication required, visit https://aka.ms/acr/authorization for more information."}
My Setup:
App Service Managed Identity:
Enabled and set to "On".
Assigned the ACR Pull role at the scope of the ACR.
ACR Managed Identity:
Enabled and set to "On".
Deployment Pipeline:
I build and push the Docker images to ACR via an Azure DevOps pipeline. Here is an excerpt from my pipeline configuration:
trigger:
- main
variables:
buildConfiguration: 'Release'
appServiceName: 'myAppService'
backendImageName: 'myregistry.azurecr.io/my-backend'
frontendImageName: 'myregistry.azurecr.io/my-frontend'
resourceGroup: 'myResourceGroup'
subscriptionId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
stages:
# Stage 1: Build and Push Docker Images
- stage: BuildAndPush
displayName: Build and Push Docker Images to Azure Container Registry
jobs:
- job: BuildAndPush
displayName: Build and Push Backend and Frontend Docker Images
pool:
vmImage: 'ubuntu-latest' # Use Ubuntu for Docker tasks
steps:
# Step 1: Login to Azure Container Registry
- task: Docker@2
displayName: Login to Azure Container Registry
inputs:
command: login
containerRegistry: 'my_container_registry'
# Step 2: Build and Push Backend Docker Image
- task: Docker@2
displayName: Build and Push Backend Docker Image
inputs:
command: buildAndPush
dockerfile: ./Dockerfile
context: ./Backend.Api
repository: my-backend
containerRegistry: 'my_container_registry'
tags: |
latest
$(Build.BuildId)
# Step 3: Build and Push Frontend Docker Image
- task: Docker@2
displayName: Build and Push Frontend Docker Image
inputs:
command: buildAndPush
dockerfile: ./Frontend.Client/Dockerfile
context: ./Frontend.Client
repository: my-frontend
containerRegistry: 'my_container_registry'
tags: |
latest
$(Build.BuildId)
# Stage 2: Deploy to Azure
- stage: Deploy
displayName: Deploy Docker Containers to Azure App Service
dependsOn: BuildAndPush
condition: succeeded()
jobs:
- job: DeployToAzure
displayName: Deploy Containers to Azure App Service
pool:
vmImage: 'ubuntu-latest'
steps:
# Step 1: Login to Azure CLI
- task: AzureCLI@2
displayName: Login to Azure
inputs:
azureSubscription: 'Azure subscription 1(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)'
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
echo "Logging in to Azure CLI"
- task: Docker@2
displayName: Login to Azure Container Registry
inputs:
command: login
containerRegistry: 'my_container_registry'
# Step 2: Generate Docker Compose File
- script: |
echo "
version: '3.8'
services:
backend:
image: $(backendImageName):latest
ports:
- 5000:80
frontend:
image: $(frontendImageName):latest
ports:
- 3000:80
" > docker-compose.yml
displayName: Generate Docker Compose File
# Step 3: Configure App Service for Multi-Container Deployment
- task: AzureCLI@2
displayName: Configure Azure App Service with Docker Compose
inputs:
azureSubscription: 'Azure subscription 1(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)'
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
az webapp config container set
--name $(appServiceName)
--resource-group $(resourceGroup)
--subscription $(subscriptionId)
--multicontainer-config-type compose
--multicontainer-config-file docker-compose.yml
# Step 4: Restart App Service to Apply Changes
- task: AzureCLI@2
displayName: Restart Azure App Service
inputs:
azureSubscription: 'Azure subscription 1(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)'
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
az webapp restart
--name $(appServiceName)
--resource-group $(resourceGroup)
--subscription $(subscriptionId)
In the final step, I configure my App Service using this docker-compose.yml file:
version: '3.8'
services:
backend:
image: <my-registry>.azurecr.io/backend:latest
ports:
- 5000:80
frontend:
image: <my-registry>.azurecr.io/frontend:latest
ports:
- 3000:80
I then restart the App Service to apply the changes.
Troubleshooting Steps So Far:
- Verified that the managed identity is enabled for both the App Service and the ACR.
- Checked that the ACR Pull role is assigned to the App Service’s managed identity.
- Confirmed that the Docker images exist in the ACR and can be pulled locally using the same docker-compose.yml.
- Checked for network restrictions or firewalls that might block the connection between the App Service and the ACR.
Despite these steps, the App Service still cannot pull the images from the ACR. The full logs are attached for additional context.
Logs Excerpt:
DockerApiException: Docker API responded with status code=InternalServerError, response={"message":"Head "https://<my-registry>.azurecr.io/v2/<image>/manifests/latest": unauthorized: authentication required, visit https://aka.ms/acr/authorization for more information."}
Questions:
- What additional configurations are required to allow the App Service to pull images from ACR using managed identity?
- Are there specific network security group (NSG) settings I need to verify?
Any help or guidance would be greatly appreciated!
I expected the Azure App Service to successfully pull the Docker images from the Azure Container Registry using the managed identity. Specifically, I anticipated that:
- The App Service would use its system-assigned managed identity to authenticate with ACR.
- The ACR Pull role would provide sufficient permissions for pulling the images.
- The containers would start successfully without any authentication or authorization issues.
2
Answers
you might need to add acrUseManagedIdentityCreds to app service configuration. refer to this link, under ‘Use managed identity to pull image from Azure Container Registry’ section.
https://learn.microsoft.com/en-us/azure/app-service/configure-custom-container?tabs=debian&pivots=container-linux#use-managed-identity-to-pull-image-from-azure-container-registry
I encountered the same issue and was able to resolve it by ensuring the Web App is configured to use its managed identity for ACR authentication. Here’s what I did:
Assign the AcrPull Role: Ensure the Web App’s system-assigned managed identity has the AcrPull role assigned to the Azure Container Registry. You can do this using the following Azure CLI command:
Enable Managed Identity Authentication: Update the Web App’s configuration to use its managed identity for ACR authentication.
Run this command:
Restart the Web App: Finally, restart the Web App to apply the changes:
After performing these steps, the Web App was able to successfully pull the container image from the ACR without any issues.