Azure Container Registry Tasks: Access network-restricted registry

Posted by  Bin Du on Friday, May 12, 2023

Registry with limited public internet access

Azure Private Link allows you to access Azure PaaS service over a private endpoint in our virtual network. After enabling private endpoint on the Azure Container Registry, you can disable public internet access and allow private link access only. However, if you use Azure Container Tasks to build and push the images or run image purge jobs which need to access the registry, you will immediately start to see access deny. It’s because ACR Tasks run on the “public” Azure machine pools whose outbound requests go through a set of public endpoints. The registry with limited or no public internet access will reject the requests from these public endpoints by default. Here are a couple of solutions.

Solution: Dedicated agent pool

If you want to disable public internet access without any exception, the best option is to use Tasks dedicated agent pool. The dedicated agent pool feature will provision the machines into your virtual network, the Tasks jobs running on the dedicated agent pool will connect to the registry through the designated private endpoint safely.

Solution: Trusted Service

Azure Container Registry also provides a trusted service mode for the registry owner to allow certain trusted Azure resources to securely bypass the registry’s network settings to perform registry operations. You can configure the ACR Tasks resource as trusted service and allow Tasks jobs to securely access the registry through public endpoints. The following are two examples using trusted service mode.

NOTE: ACR Tasks only supports system-assigned identity in trusted mode and you also need to disable the default auth mode on the trusted task.

Example: Purge images task

  • This example is based on the the flow described here.

    # Prerequisite
    # 1) Install azure-cli
    
    registry_name="myregistry"
    task_name="mypurgetask"
    cmd="acr purge --filter 'hello-world:.*' --untagged --ago 1d --dry-run"
    
    echo "enable trusted service on registry: $registry_name"
    registry_login_server=$(az acr update -n $registry_name --allow-trusted-services true --query "loginServer" -o tsv)
    echo "registry login server: $registry_login_server"
    
    echo "create task with system identity enabled: $task_name"
    system_identity_principal=$(az acr task create -r $registry_name -n $task_name --cmd "$cmd" -c /dev/null --assign-identity [system] --auth-mode None --base-image-trigger-enabled false --query "identity.principalId" -o tsv)
    echo "system identity principal: $system_identity_principal"
    
    registry_resource_id=$(az acr show -n $registry_name --query "id" -o tsv)
    
    echo "assign AcrPush role to the system ideneity for registry: $registry_resource_id"
    az role assignment create --role AcrPush --assignee-object-id $system_identity_principal --assignee-principal-type ServicePrincipal --scope $registry_resource_id
    
    echo "enable system identity login on registry: $registry_login_server"
    az acr task credential add -r $registry_name -n $task_name --login-server $registry_login_server --use-identity [system]
    
    az acr task run -r $registry_name -n $task_name
    

Example: Build with local source

  • If you want to run ad-hoc container image build with trusted service mode, you need to first create a placeholder task resource in the registry with the following acb.yaml. It is one-time setup.

    version: v1.1.0
    steps:
    - build: -t $Registry/{{.Values.image}} -f {{.Values.dockerfile}} .
    - push:
        - $Registry/{{.Values.image}}
    
    # Prerequisite
    # 1) Install azure-cli
    
    registry_name="myregistry"
    task_name="mybuildtask"
    
    echo "enable trusted service on registry: $registry_name"
    registry_login_server=$(az acr update -n $registry_name --allow-trusted-services true --query "loginServer" -o tsv)
    echo "registry login server: $registry_login_server"
    
    echo "create task with system identity enabled: $task_name"
    system_identity_principal=$(az acr task create -r $registry_name -n $task_name -f acb.yaml -c /dev/null --assign-identity [system] --auth-mode None --base-image-trigger-enabled false --query "identity.principalId" -o tsv)
    echo "system identity principal: $system_identity_principal"
    
    registry_resource_id=$(az acr show -n $registry_name --query "id" -o tsv)
    
    echo "assign AcrPush role to the system ideneity for registry: $registry_resource_id"
    az role assignment create --role AcrPush --assignee-object-id $system_identity_principal --assignee-principal-type ServicePrincipal --scope $registry_resource_id
    
    echo "enable system identity login on registry: $registry_login_server"
    az acr task credential add -r $registry_name -n $task_name --login-server $registry_login_server --use-identity [system]
    
  • Schedule the task run with the local source to build/push the image to the registry.

    registry_name="myregistry"
    task_name="mybuildtask"
    
    az acr task run -r $registry_name -n $task_name --set image=myrepo:mytag --set dockerfile=Dockerfile -c .
    

Solution: Configure public IP network rules

Tasks reserve a set of public IPs in each region (a.k.a. AzureContainerRegistry Service Tag) for outbound requests. You can choose to add the IPs in the firewall allowed list.

Query AzureContainerRegistry Service Tag IPs

Tasks agent pools are running on the same region where the registry is created. Once you confirm the registry home region, you can use it to query the regional Service Tag IPs. The following example shows the az command to query the IPs (both IPv4 and IPv6) in EastUS region.

# Prerequisite
# 1) Install azure-cli

az network list-service-tags --location eastus --query "values[?id == 'AzureContainerRegistry.EastUS'].properties.addressPrefixes[]" -o tsv
  • 20.42.66.0/24
  • 20.42.67.0/24
  • 20.42.74.64/26
  • 20.62.128.0/26
  • 40.71.10.216/29
  • 40.78.226.208/29
  • 40.78.231.0/24
  • 40.79.154.104/29
  • 52.168.112.192/26
  • 52.168.114.0/24
  • 52.168.115.0/24
  • 2603:1030:210:402::90/125
  • 2603:1030:210:402::340/122
  • 2603:1030:210:402::580/121
  • 2603:1030:210:802::90/125
  • 2603:1030:210:802::2c0/122
  • 2603:1030:210:802::400/121
  • 2603:1030:210:c02::90/125
  • 2603:1030:210:c02::400/121

Allow Service Tag IPv4 in ACR firewall

ACR firewall rule currently only supports IPv4 CIDR. In the above example, IPv4 CIDR is highlighted. You can add them to the ACR firewall IP rules using Azure Portal or AZ CLI.

# Prerequisite
# 1) Install azure-cli

az acr network-rule add -n myregistry --ip-address "20.42.66.0/24"
az acr network-rule add -n myregistry --ip-address "20.42.67.0/24"
az acr network-rule add -n myregistry --ip-address "20.42.74.64/26"
...

Tasks agent pool IP vs Github and Azure DevOps agent pool IP

Tasks provides several commands (eg az acr build, az acr run and az acr task run) in Azure CLI to allow you to trigger the build or run jobs. You can run the commands locally from your dev machine or in your Github and Azure DevOps pipelines. These commands run on your local machine or the Github and Azure DevOps agent pools machines. However, the build and run jobs run on the Tasks agent pool machines. The IPs of the Github and Azure DevOps agent pool are different from the Tasks agent pool. When you configure the registry firewall rules, you need to make sure you add the IPs of the Tasks agent pool which you can query from the AzureContainerRegistry Service Tag.