* Add azure-container-registry-cli skill * Address Copilot review: 2025 ACR changes (ABAC, zone redundancy, task network bypass) and secure credential handling * Add ACI (Azure Container Instances) to codespell ignore list * Address second Copilot review wave: DCT deprecation, purge --untagged caveat, soft-delete tiers, Catalog Lister scope, secret quoting --------- Co-authored-by: Aaron Powell <me@aaron-powell.com>
6.8 KiB
Networking & Geo-Replication
Table of Contents
- Geo-Replication
- Zone Redundancy
- Private Endpoints (Private Link)
- Public Network Rules
- Dedicated Data Endpoints
- Connected Registry
- Registry Transfer Pipelines
Geo-replication, private endpoints, public IP network rules, dedicated data endpoints, connected registries, and transfer pipelines require the Premium SKU. Zone redundancy is automatic in every tier.
Geo-Replication
One registry, one login server, images served from the nearest region:
az acr replication create --registry {registry} --location westeurope
az acr replication list --registry {registry} --output table
az acr replication show --registry {registry} --name westeurope
az acr replication delete --registry {registry} --name westeurope
# Regional endpoint status (useful for webhook/replication debugging)
az acr replication update --registry {registry} --name westeurope --region-endpoint-enabled true
Pushes replicate automatically; clients keep pulling {registry}.azurecr.io and Traffic Manager routes to the closest replica.
Zone Redundancy
Zone redundancy is enabled automatically for all registries, in all tiers (Basic/Standard/Premium), in regions that support availability zones — no flag, SKU, or action required, and it cannot be disabled. Geo-replicas in supported regions are also zone-redundant by default.
Do not rely on the zoneRedundancy property or the legacy --zone-redundancy flag: the property is a deprecated artifact that may display Disabled even though the registry is fully zone-redundant. Registries in regions without availability-zone support are the only exception — migrate them (via az acr import or a transfer pipeline) to a supported region.
Private Endpoints (Private Link)
# 1. Disable network policies on the endpoint subnet if needed, then create the endpoint
az network private-endpoint create --resource-group {rg} --name {registry}-pe \
--vnet-name {vnet} --subnet {subnet} \
--private-connection-resource-id $(az acr show --name {registry} --query id --output tsv) \
--group-ids registry \
--connection-name {registry}-pe-conn
# 2. Private DNS so {registry}.azurecr.io resolves to the private IP
az network private-dns zone create --resource-group {rg} --name privatelink.azurecr.io
az network private-dns link vnet create --resource-group {rg} \
--zone-name privatelink.azurecr.io --name {registry}-dns-link --virtual-network {vnet} --registration-enabled false
az network private-endpoint dns-zone-group create --resource-group {rg} \
--endpoint-name {registry}-pe --name default \
--private-dns-zone privatelink.azurecr.io --zone-name registry
# 3. Optionally shut off public access entirely
az acr update --name {registry} --public-network-enabled false
# Manage connection approvals
az acr private-endpoint-connection list --registry-name {registry} --output table
az acr private-endpoint-connection approve --registry-name {registry} --name {connection}
Notes:
- Each private endpoint creates records for the registry and its data endpoint(s) (
{registry}.{region}.data.azurecr.io) — geo-replicated registries need one data record per region. - With public access disabled, standard ACR Tasks agents cannot reach the registry — use a dedicated agent pool attached to a subnet in the VNet, or enable trusted services and the task network bypass policy (see below).
Public Network Rules
Restrict public access to specific IPs instead of (or before) going fully private:
# Default-deny, then allow specific ranges
az acr update --name {registry} --default-action Deny
az acr network-rule add --name {registry} --ip-address 203.0.113.0/24
az acr network-rule list --name {registry}
az acr network-rule remove --name {registry} --ip-address 203.0.113.0/24
# Let trusted Azure services (e.g., Defender, ACI, image import) through the firewall
az acr update --name {registry} --allow-trusted-services true
⚠️ Since June 1, 2025, --allow-trusted-services alone is NOT enough for ACR Tasks using a system-assigned managed identity — without the task network bypass policy, their runs get 403 errors on a network-restricted registry. Enable it explicitly:
az resource update \
--namespace Microsoft.ContainerRegistry --resource-type registries \
--name {registry} --resource-group {rg} \
--api-version 2025-06-01-preview \
--set properties.networkRuleBypassAllowedForTasks=true
Alternatives that avoid the bypass entirely: run tasks in a VNet-attached agent pool, or run acr purge locally with the acr-cli binary. Tasks using a user-assigned identity are not affected.
Dedicated Data Endpoints
Give layer downloads stable, registry-specific FQDNs ({registry}.{region}.data.azurecr.io) instead of shared storage endpoints — simplifies client-side firewall rules:
az acr update --name {registry} --data-endpoint-enabled true
az acr show-endpoints --name {registry}
Connected Registry
On-premises / IoT edge mirror of a cloud registry:
# Parent registry must have a dedicated data endpoint
az acr update --name {registry} --data-endpoint-enabled true
az acr connected-registry create --registry {registry} --name {connected-name} \
--repository "app" "hello-world" \
--mode ReadOnly # or ReadWrite
az acr connected-registry list --registry {registry} --output table
az acr connected-registry get-settings --registry {registry} --name {connected-name} \
--parent-protocol https --generate-password 1
az acr connected-registry deactivate --registry {registry} --name {connected-name}
Registry Transfer Pipelines
Move images between disconnected clouds/tenants via storage blobs (extension acrtransfer):
az extension add --name acrtransfer
# Export from source registry to a storage container (SAS token in Key Vault)
az acr export-pipeline create --resource-group {rg} --registry {src-registry} \
--name export-pipe \
--secret-uri https://{vault}.vault.azure.net/secrets/{sas-secret} \
--storage-container-uri https://{account}.blob.core.windows.net/{container}
# Import on the target side
az acr import-pipeline create --resource-group {rg} --registry {dst-registry} \
--name import-pipe \
--secret-uri https://{vault}.vault.azure.net/secrets/{sas-secret} \
--storage-container-uri https://{account}.blob.core.windows.net/{container}
# Run an export
az acr pipeline-run create --resource-group {rg} --registry {src-registry} \
--pipeline export-pipe --name run1 --pipeline-type export \
--artifacts app:v1 app:v2 --storage-blob transfer-blob-1
For simple same-cloud copies prefer az acr import (see images-and-artifacts.md).