Azure Container Registry
Auth
ocync auto-detects ACR (*.azurecr.io, *.azurecr.cn, *.azurecr.us) and authenticates against ACR’s proprietary OAuth2 endpoints (not standard OCI Bearer exchange) via a four-source Azure AD credential chain:
- Client secret (
AZURE_CLIENT_ID,AZURE_CLIENT_SECRET,AZURE_TENANT_ID) - Workload Identity (
AZURE_FEDERATED_TOKEN_FILE; AKS Workload Identity or any OIDC federation) - Managed Identity (
IDENTITY_ENDPOINT/IDENTITY_HEADER; AKS pod-managed identity, App Service, Functions) - Azure CLI (
az login; developer machines)
See the Azure DefaultAzureCredential docs for credential precedence.
Notable behaviors:
- Two-step OAuth2 exchange: AAD access token ->
POST /oauth2/exchange-> ACR refresh token (~3h) ->POST /oauth2/tokenwith scope -> ACR access token (~75min). TTLs are driven by the JWTexpclaim. - Sovereign cloud routing:
*.azurecr.cnuseslogin.chinacloudapi.cn;*.azurecr.ususeslogin.microsoftonline.us. The hostname suffix selects both the AAD authority and the ACR resource endpoint. - ~20 MB streaming PUT body limit. ACR rejects streaming uploads above ~20 MB with a connection reset or 413; chunked PATCH fallback is not yet implemented. Blobs exceeding this limit cannot currently be pushed to ACR.
- Two rate-limit windows: ACR enforces separate ReadOps and WriteOps quotas; ocync tracks them as two AIMD windows.
CLI example
# After `az login`, push from Chainguard to ACR. ocync uses the Azure CLI
# credential source from the chain.
ocync copy \
cgr.dev/chainguard/static:latest \
myregistry.azurecr.io/static:latest
Sync-mode:
# ocync.yaml
registries:
src: { url: cgr.dev }
acr: { url: myregistry.azurecr.io }
defaults:
source: src
targets: acr
mappings:
- from: chainguard/static
to: static
ocync sync --config ocync.yaml
Kubernetes deployment
On AKS, use Azure AD Workload Identity. The chart’s workloadIdentity.azure block sets both the ServiceAccount annotations (azure.workload.identity/client-id and optionally tenant-id) AND the critical pod label azure.workload.identity/use: "true" — without the pod label, the AAD webhook does not inject the projected SA token, and the credential chain falls through to managed identity or Azure CLI (which won’t be available in a pod).
# values.yaml
config:
registries:
src: { url: cgr.dev }
acr: { url: myregistry.azurecr.io }
defaults:
source: src
targets: acr
mappings:
- from: chainguard/static
to: static
workloadIdentity:
provider: azure
azure:
clientId: 00000000-0000-0000-0000-000000000000
tenantId: 11111111-1111-1111-1111-111111111111 # optional
For sovereign clouds, the AAD authority is selected automatically from the registry hostname suffix; the chart values are unchanged. Configuring the AAD app, federated identity credential, and ACR AcrPull role assignment is the user’s IAM/AAD work; see Azure Workload Identity docs.
For other secret-injection patterns, see Kubernetes secret patterns.