From 785e2f993510bf8ae54a6cc6f347db6e059580fb Mon Sep 17 00:00:00 2001 From: Adrien Clerbois Date: Mon, 27 Jul 2026 11:30:51 +0200 Subject: [PATCH 1/4] Add azure-container-registry-cli skill --- docs/README.skills.md | 1 + skills/azure-container-registry-cli/SKILL.md | 90 ++++++++++ .../references/auth-and-security.md | 145 +++++++++++++++ .../references/build-and-tasks.md | 137 ++++++++++++++ .../references/images-and-artifacts.md | 167 ++++++++++++++++++ .../references/networking-and-geo.md | 138 +++++++++++++++ 6 files changed, 678 insertions(+) create mode 100644 skills/azure-container-registry-cli/SKILL.md create mode 100644 skills/azure-container-registry-cli/references/auth-and-security.md create mode 100644 skills/azure-container-registry-cli/references/build-and-tasks.md create mode 100644 skills/azure-container-registry-cli/references/images-and-artifacts.md create mode 100644 skills/azure-container-registry-cli/references/networking-and-geo.md diff --git a/docs/README.skills.md b/docs/README.skills.md index b5d39afd2..5d8e12b25 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -70,6 +70,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to | [aws-well-architected-review](../skills/aws-well-architected-review/SKILL.md)
`gh skills install github/awesome-copilot aws-well-architected-review` | Perform an AWS Well-Architected Framework review of the current workload IaC and architecture, generating findings and GitHub issues for improvements. | None | | [az-cost-optimize](../skills/az-cost-optimize/SKILL.md)
`gh skills install github/awesome-copilot az-cost-optimize` | Analyze Azure resources used in the app (IaC files and/or resources in a target rg) and optimize costs - creating GitHub issues for identified optimizations. | None | | [azure-architecture-autopilot](../skills/azure-architecture-autopilot/SKILL.md)
`gh skills install github/awesome-copilot azure-architecture-autopilot` | Design Azure infrastructure using natural language, or analyze existing Azure resources to auto-generate architecture diagrams, refine them through conversation, and deploy with Bicep.
When to use this skill: - "Create X on Azure", "Set up a RAG architecture" (new design) - "Analyze my current Azure infrastructure", "Draw a diagram for rg-xxx" (existing analysis) - "Foundry is slow", "I want to reduce costs", "Strengthen security" (natural language modification) - Azure resource deployment, Bicep template generation, IaC code generation - Microsoft Foundry, AI Search, OpenAI, Fabric, ADLS Gen2, Databricks, and all Azure services | `.gitignore`
`assets/06-architecture-diagram.png`
`assets/07-azure-portal-resources.png`
`assets/08-deployment-succeeded.png`
`references/ai-data.md`
`references/architecture-guidance-sources.md`
`references/azure-common-patterns.md`
`references/azure-dynamic-sources.md`
`references/bicep-generator.md`
`references/bicep-reviewer.md`
`references/phase0-scanner.md`
`references/phase1-advisor.md`
`references/phase4-deployer.md`
`references/service-gotchas.md`
`scripts/cli.py`
`scripts/generator.py`
`scripts/icons.py` | +| [azure-container-registry-cli](../skills/azure-container-registry-cli/SKILL.md)
`gh skills install github/awesome-copilot azure-container-registry-cli` | Manage Azure Container Registry via the az acr CLI including registries, images, cloud builds, ACR Tasks, authentication, tokens, geo-replication, and networking. Use when working with ACR, az acr commands, pushing/importing/purging container images in Azure, or when the user mentions Azure Container Registry. | `references/auth-and-security.md`
`references/build-and-tasks.md`
`references/images-and-artifacts.md`
`references/networking-and-geo.md` | | [azure-deployment-preflight](../skills/azure-deployment-preflight/SKILL.md)
`gh skills install github/awesome-copilot azure-deployment-preflight` | Performs comprehensive preflight validation of Bicep deployments to Azure, including template syntax validation, what-if analysis, and permission checks. Use this skill before any deployment to Azure to preview changes, identify potential issues, and ensure the deployment will succeed. Activate when users mention deploying to Azure, validating Bicep files, checking deployment permissions, previewing infrastructure changes, running what-if, or preparing for azd provision. | `references/ERROR-HANDLING.md`
`references/REPORT-TEMPLATE.md`
`references/VALIDATION-COMMANDS.md` | | [azure-devops-cli](../skills/azure-devops-cli/SKILL.md)
`gh skills install github/awesome-copilot azure-devops-cli` | Manage Azure DevOps resources via CLI including projects, repos, pipelines, builds, pull requests, work items, artifacts, and service endpoints. Use when working with Azure DevOps, az commands, devops automation, CI/CD, or when user mentions Azure DevOps CLI. | `references/advanced-usage.md`
`references/boards-and-iterations.md`
`references/long-comments-on-windows.md`
`references/org-and-security.md`
`references/pipelines-and-builds.md`
`references/repos-and-prs.md`
`references/variables-and-agents.md`
`references/workflows-and-patterns.md` | | [azure-pricing](../skills/azure-pricing/SKILL.md)
`gh skills install github/awesome-copilot azure-pricing` | Fetches real-time Azure retail pricing using the Azure Retail Prices API (prices.azure.com) and estimates Copilot Studio agent credit consumption. Use when the user asks about the cost of any Azure service, wants to compare SKU prices, needs pricing data for a cost estimate, mentions Azure pricing, Azure costs, Azure billing, or asks about Copilot Studio pricing, Copilot Credits, or agent usage estimation. Covers compute, storage, networking, databases, AI, Copilot Studio, and all other Azure service families. | `references/COPILOT-STUDIO-RATES.md`
`references/COST-ESTIMATOR.md`
`references/REGIONS.md`
`references/SERVICE-NAMES.md` | diff --git a/skills/azure-container-registry-cli/SKILL.md b/skills/azure-container-registry-cli/SKILL.md new file mode 100644 index 000000000..ab072d951 --- /dev/null +++ b/skills/azure-container-registry-cli/SKILL.md @@ -0,0 +1,90 @@ +--- +name: azure-container-registry-cli +description: Manage Azure Container Registry via the az acr CLI including registries, images, cloud builds, ACR Tasks, authentication, tokens, geo-replication, and networking. Use when working with ACR, az acr commands, pushing/importing/purging container images in Azure, or when the user mentions Azure Container Registry. +--- + +# Azure Container Registry CLI + +Manage Azure Container Registry (ACR) resources using the `az acr` command group of the Azure CLI. + +**CLI:** `az acr` ships with core Azure CLI — no extension required (the `acrtransfer` extension is only needed for export/import pipelines). + +## Prerequisites + +```bash +# Install Azure CLI +brew install azure-cli # macOS +curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash # Linux +winget install Microsoft.AzureCLI # Windows + +# Sign in and select subscription +az login +az account set --subscription {subscription-id} +``` + +## Quick Start + +```bash +# Create a registry (SKU: Basic | Standard | Premium) +az acr create --resource-group {rg} --name {registry} --sku Standard + +# Authenticate Docker/Podman against the registry +az acr login --name {registry} + +# Build and push in the cloud — no local Docker needed +az acr build --registry {registry} --image app:v1 . + +# Copy an image from another registry without pull/push +az acr import --name {registry} --source mcr.microsoft.com/hello-world:latest + +# List repositories and tags +az acr repository list --name {registry} --output table +az acr repository show-tags --name {registry} --repository app --orderby time_desc + +# Diagnose registry connectivity and configuration +az acr check-health --name {registry} --yes +``` + +## Key Principles + +- **Prefer `az acr build` / ACR Tasks** over local `docker build` + `docker push`: builds run in Azure, work without a local daemon, and integrate with triggers. +- **Prefer `az acr import`** to move images between registries: it is server-side, faster, and requires no local storage. +- **Never enable the admin user for production** — use Microsoft Entra identities (RBAC roles `AcrPull`/`AcrPush`), repository-scoped tokens, or managed identities. +- **Premium-only features**: geo-replication, private endpoints, tokens/scope maps, retention policies, connected registries, agent pools, zone redundancy. + +## CLI Structure + +``` +az acr +├── create / delete / list / show / update # Registry lifecycle +├── login # Docker credential helper (or --expose-token) +├── check-health / check-name / show-usage # Diagnostics & quota +├── build # Cloud image build (quick task) +├── run # Run a command / multi-step task once +├── task # ACR Tasks (triggers, timers, logs, runs) +├── agentpool # Dedicated task agent pools (Premium) +├── import # Server-side image copy into the registry +├── repository # List/show/delete/untag repos & tags, lock images +├── manifest # Manifest metadata, delete, OCI referrers +├── credential # Admin user credentials (avoid in production) +├── token / scope-map # Repository-scoped tokens (Premium) +├── replication # Geo-replication (Premium) +├── network-rule # IP network rules +├── private-endpoint-connection # Private Link approvals +├── config # content-trust, retention, soft-delete, ... +├── cache / credential-set # Artifact cache (pull-through cache) rules +├── webhook # Push/delete event webhooks +├── connected-registry # On-premises / IoT connected registries +└── export-pipeline / import-pipeline / pipeline-run # acrtransfer extension +``` + +## Reference Files + +Read the relevant reference file based on the user's task. Each file contains complete command syntax and examples for its domain. + +| File | When to read | Covers | +|---|---|---| +| `references/auth-and-security.md` | Login failures, permissions, CI/CD or AKS pull access | `az acr login` (incl. `--expose-token`), Entra RBAC roles, service principals, managed identities, `--attach-acr` for AKS, repository-scoped tokens & scope maps, admin user, content trust | +| `references/build-and-tasks.md` | Building images in Azure, automation, CI triggers | `az acr build`, `az acr run`, multi-step task YAML, `az acr task` (git/base-image/timer triggers, logs, runs), agent pools | +| `references/images-and-artifacts.md` | Managing repos, tags, cleanup, storage costs | `az acr import`, repository & manifest commands, untag vs delete, purge (`acr purge`), image locking, retention policy, soft delete, artifact cache, `show-usage` | +| `references/networking-and-geo.md` | Multi-region, private access, edge scenarios | Geo-replication, zone redundancy, private endpoints, network rules, dedicated data endpoints, connected registries, registry transfer pipelines | diff --git a/skills/azure-container-registry-cli/references/auth-and-security.md b/skills/azure-container-registry-cli/references/auth-and-security.md new file mode 100644 index 000000000..cc92e14c2 --- /dev/null +++ b/skills/azure-container-registry-cli/references/auth-and-security.md @@ -0,0 +1,145 @@ +# Authentication & Security + +## Table of Contents +- [Individual Login](#individual-login) +- [Microsoft Entra RBAC Roles](#microsoft-entra-rbac-roles) +- [Service Principals](#service-principals) +- [Managed Identities](#managed-identities) +- [AKS Integration](#aks-integration) +- [Repository-Scoped Tokens](#repository-scoped-tokens) +- [Admin User](#admin-user) +- [Content Trust](#content-trust) + +--- + +## Individual Login + +```bash +# Standard login — wires Docker/Podman credentials via your az login identity +az acr login --name {registry} + +# Without a Docker daemon: get an Entra access token for the registry +az acr login --name {registry} --expose-token +# Returns accessToken + loginServer; use with: +docker login {registry}.azurecr.io --username 00000000-0000-0000-0000-000000000000 --password-stdin +``` + +Notes: +- `az acr login` tokens are valid for 3 hours; re-run on expiry. +- The full login server name is always `{registry}.azurecr.io` (lowercase). + +## Microsoft Entra RBAC Roles + +Built-in roles for data-plane access: + +| Role | Permissions | +|---|---| +| `AcrPull` | Pull images | +| `AcrPush` | Pull + push images | +| `AcrDelete` | Delete images | +| `AcrImageSigner` | Sign images (content trust) | +| `Contributor`/`Owner` | Full control-plane management + push/pull | + +```bash +# Get the registry resource ID +ACR_ID=$(az acr show --name {registry} --query id --output tsv) + +# Grant pull access to a user, group, service principal, or managed identity +az role assignment create --assignee {principal-id} --scope $ACR_ID --role AcrPull + +# List who has access +az role assignment list --scope $ACR_ID --output table +``` + +## Service Principals + +For CI/CD systems that cannot use OIDC/managed identity: + +```bash +# Create an SP scoped to pull only +ACR_ID=$(az acr show --name {registry} --query id --output tsv) +az ad sp create-for-rbac --name {sp-name} --scopes $ACR_ID --role AcrPull + +# Docker login with the SP +docker login {registry}.azurecr.io --username {appId} --password {password} +``` + +Prefer federated credentials (OIDC) over SP passwords in GitHub Actions / Azure DevOps when possible. + +## Managed Identities + +For Azure compute (VM, App Service, Container Apps, Functions): + +```bash +# Assign a system-assigned identity and grant it pull +az vm identity assign --name {vm} --resource-group {rg} +PRINCIPAL_ID=$(az vm show --name {vm} --resource-group {rg} --query identity.principalId --output tsv) +az role assignment create --assignee $PRINCIPAL_ID --scope $ACR_ID --role AcrPull +``` + +App Service / Container Apps then pull with `--assign-identity` + `--acr-identity` style flags of their own CLIs — no registry password needed. + +## AKS Integration + +```bash +# Attach at cluster creation +az aks create --name {cluster} --resource-group {rg} --attach-acr {registry} + +# Attach/detach an existing cluster (grants AcrPull to the kubelet identity) +az aks update --name {cluster} --resource-group {rg} --attach-acr {registry} +az aks update --name {cluster} --resource-group {rg} --detach-acr {registry} + +# Validate the cluster can reach the registry +az aks check-acr --name {cluster} --resource-group {rg} --acr {registry}.azurecr.io +``` + +`--attach-acr` requires Owner or User Access Administrator on the registry. Cross-subscription attach works by passing the full ACR resource ID. + +## Repository-Scoped Tokens + +Premium SKU. Fine-grained, non-Entra credentials (e.g., external partners, IoT devices): + +```bash +# 1. Create a scope map (actions: content/read, content/write, content/delete, metadata/read, metadata/write) +az acr scope-map create --name {scope-map} --registry {registry} \ + --repository app content/read metadata/read \ + --description "Pull-only access to app" + +# 2. Create a token bound to the scope map +az acr token create --name {token} --registry {registry} --scope-map {scope-map} + +# 3. Generate/rotate passwords (up to 2, optional expiry) +az acr token credential generate --name {token} --registry {registry} --password1 --expiration-in-days 30 + +# Login with the token +docker login {registry}.azurecr.io --username {token} --password {token-password} + +# Disable or delete +az acr token update --name {token} --registry {registry} --status disabled +az acr token delete --name {token} --registry {registry} --yes +``` + +## Admin User + +Single account, full push/pull on the whole registry, not auditable per user — **keep disabled in production**: + +```bash +az acr update --name {registry} --admin-enabled false # recommended +az acr credential show --name {registry} # view username/passwords (if enabled) +az acr credential renew --name {registry} --password-name password2 # rotate +``` + +Legitimate uses: quick local tests, services that only accept username/password and cannot use tokens. + +## Content Trust + +```bash +# Enable Docker Content Trust support (Premium) +az acr config content-trust update --registry {registry} --status enabled + +# Client side: push signed images +export DOCKER_CONTENT_TRUST=1 +docker push {registry}.azurecr.io/app:v1 +``` + +Signers need `AcrImageSigner` in addition to `AcrPush`. For new projects prefer Notation/ORAS-based signing over Docker Content Trust. diff --git a/skills/azure-container-registry-cli/references/build-and-tasks.md b/skills/azure-container-registry-cli/references/build-and-tasks.md new file mode 100644 index 000000000..5070fc64c --- /dev/null +++ b/skills/azure-container-registry-cli/references/build-and-tasks.md @@ -0,0 +1,137 @@ +# Builds & ACR Tasks + +## Table of Contents +- [Quick Build (az acr build)](#quick-build-az-acr-build) +- [Run a Command or Multi-Step Task Once (az acr run)](#run-a-command-or-multi-step-task-once-az-acr-run) +- [ACR Tasks (az acr task)](#acr-tasks-az-acr-task) +- [Triggers](#triggers) +- [Multi-Step Task YAML](#multi-step-task-yaml) +- [Agent Pools](#agent-pools) + +--- + +## Quick Build (az acr build) + +Builds in Azure and pushes to the registry — no local Docker daemon required: + +```bash +# Build from the current directory and push +az acr build --registry {registry} --image app:v1 . + +# Custom Dockerfile, build args, target platform +az acr build --registry {registry} --image app:v1 \ + --file docker/Dockerfile.prod \ + --build-arg VERSION=1.2.3 \ + --platform linux/amd64 . + +# Multi-arch: run one build per platform (linux/amd64, linux/arm64, windows/amd64) +az acr build --registry {registry} --image app:v1-arm64 --platform linux/arm64 . + +# Build directly from a Git repo (no local clone) +az acr build --registry {registry} --image app:v1 https://github.com/{org}/{repo}.git#{branch}:{folder} + +# Build without pushing (validation only) +az acr build --registry {registry} --image app:test --no-push . +``` + +Notes: +- The build context is uploaded; use a `.dockerignore` to keep it small. +- Tag with a unique value per build (git SHA, run ID) — avoid relying on `latest`. + +## Run a Command or Multi-Step Task Once (az acr run) + +```bash +# Run a container command in the registry's task runner (context /dev/null = no upload) +az acr run --registry {registry} --cmd '{registry}.azurecr.io/app:v1' /dev/null + +# Execute a multi-step task file against the current directory +az acr run --registry {registry} --file acb.yaml . +``` + +## ACR Tasks (az acr task) + +Persistent, triggerable build definitions: + +```bash +# Create a task that builds on every commit to main +az acr task create --registry {registry} --name build-app \ + --image "app:{{.Run.ID}}" \ + --context https://github.com/{org}/{repo}.git#main \ + --file Dockerfile \ + --git-access-token {pat} \ + --commit-trigger-enabled true \ + --base-image-trigger-enabled true + +# Manually trigger, list, inspect +az acr task run --registry {registry} --name build-app +az acr task list --registry {registry} --output table +az acr task list-runs --registry {registry} --name build-app --output table +az acr task logs --registry {registry} --name build-app # latest run +az acr task logs --registry {registry} --run-id {run-id} + +# Update / disable / delete +az acr task update --registry {registry} --name build-app --image "app:{{.Run.ID}}" +az acr task update --registry {registry} --name build-app --status Disabled +az acr task delete --registry {registry} --name build-app --yes +``` + +Useful run variables for `--image`: `{{.Run.ID}}`, `{{.Run.Commit}}`, `{{.Run.Branch}}`, `{{.Run.Date}}`. + +## Triggers + +```bash +# Timer trigger (cron in UTC) — e.g., nightly rebuild +az acr task timer add --registry {registry} --name build-app \ + --timer-name nightly --schedule "0 2 * * *" +az acr task timer list --registry {registry} --name build-app +az acr task timer remove --registry {registry} --name build-app --timer-name nightly +``` + +- **Commit trigger**: rebuild on push to the tracked branch (`--commit-trigger-enabled`). +- **Base image trigger**: rebuild automatically when the base image (e.g., a patched `mcr.microsoft.com` image) is updated (`--base-image-trigger-enabled`) — key for OS/framework patching. +- **Timer trigger**: cron schedules; also the standard way to schedule `acr purge` cleanup (see `images-and-artifacts.md`). + +Tasks that access other registries or Azure resources can use an identity: + +```bash +az acr task identity assign --registry {registry} --name build-app # system-assigned +az acr task credential add --registry {registry} --name build-app \ + --login-server {other-registry}.azurecr.io --use-identity [system] +``` + +## Multi-Step Task YAML + +`acb.yaml` — build, test, then push only on success: + +```yaml +version: v1.1.0 +steps: + - build: -t $Registry/app:{{.Run.ID}} -f Dockerfile . + - cmd: $Registry/app:{{.Run.ID}} run-tests + - push: + - $Registry/app:{{.Run.ID}} +``` + +```bash +# Run once +az acr run --registry {registry} --file acb.yaml . + +# Or create a triggered task from the YAML +az acr task create --registry {registry} --name build-test-push \ + --file acb.yaml \ + --context https://github.com/{org}/{repo}.git#main \ + --git-access-token {pat} +``` + +## Agent Pools + +Premium SKU. Dedicated task compute — required when the registry is behind a firewall/VNet, or for more CPU: + +```bash +az acr agentpool create --registry {registry} --name pool1 --tier S2 # S1/S2/S3/I6 +az acr agentpool list --registry {registry} --output table + +# Target the pool +az acr build --registry {registry} --agent-pool pool1 --image app:v1 . +az acr task create --registry {registry} --name build-app --agent-pool pool1 ... +``` diff --git a/skills/azure-container-registry-cli/references/images-and-artifacts.md b/skills/azure-container-registry-cli/references/images-and-artifacts.md new file mode 100644 index 000000000..b10cde174 --- /dev/null +++ b/skills/azure-container-registry-cli/references/images-and-artifacts.md @@ -0,0 +1,167 @@ +# Images & Artifacts + +## Table of Contents +- [Import Images (Server-Side Copy)](#import-images-server-side-copy) +- [Repositories & Tags](#repositories--tags) +- [Manifests](#manifests) +- [Untag vs Delete](#untag-vs-delete) +- [Purge Old Images (acr purge)](#purge-old-images-acr-purge) +- [Lock Images](#lock-images) +- [Retention Policy & Soft Delete](#retention-policy--soft-delete) +- [Artifact Cache (Pull-Through Cache)](#artifact-cache-pull-through-cache) +- [Storage Usage](#storage-usage) + +--- + +## Import Images (Server-Side Copy) + +Preferred over `docker pull` + `docker push` — no local storage, keeps multi-arch manifests intact: + +```bash +# From a public registry +az acr import --name {registry} --source mcr.microsoft.com/hello-world:latest +az acr import --name {registry} --source docker.io/library/nginx:1.27 --image nginx:1.27 + +# From another ACR in the same tenant (by resource ID, no credentials needed) +az acr import --name {registry} \ + --source app:v1 \ + --registry /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.ContainerRegistry/registries/{src-registry} + +# From a private registry with credentials +az acr import --name {registry} --source private.example.com/app:v1 \ + --username {user} --password {password} + +# Overwrite an existing tag +az acr import --name {registry} --source docker.io/library/nginx:1.27 --image nginx:1.27 --force +``` + +## Repositories & Tags + +```bash +az acr repository list --name {registry} --output table + +# Tags, newest first, with digest and timestamps +az acr repository show-tags --name {registry} --repository app \ + --orderby time_desc --detail --output table + +az acr repository show --name {registry} --image app:v1 # tag attributes +az acr repository show --name {registry} --repository app # repo attributes +``` + +## Manifests + +```bash +# Metadata for all manifests in a repo (digest, tags, size, timestamps) +az acr manifest list-metadata --registry {registry} --name app --output table + +# One manifest's metadata / raw content +az acr manifest show-metadata --registry {registry} --name app:v1 +az acr manifest show --registry {registry} --name app@sha256:{digest} + +# Find untagged (orphaned) manifests +az acr manifest list-metadata --registry {registry} --name app \ + --query "[?tags==null].digest" --output tsv +``` + +## Untag vs Delete + +```bash +# Untag: removes only the tag; manifest + layers remain (still pullable by digest) +az acr repository untag --name {registry} --image app:v1 + +# Delete by tag: deletes the whole manifest and ALL other tags pointing to it +az acr repository delete --name {registry} --image app:v1 --yes + +# Delete by digest (precise) +az acr repository delete --name {registry} --image app@sha256:{digest} --yes + +# Delete an entire repository +az acr repository delete --name {registry} --repository app --yes +``` + +⚠️ Deleting by tag deletes the underlying manifest — other tags on the same image disappear too. Untag first if you only want to retire a tag name. + +## Purge Old Images (acr purge) + +`acr purge` runs as an ACR Task (container `mcr.microsoft.com/acr/acr-cli`): + +```bash +# Dry run first — ALWAYS +az acr run --registry {registry} \ + --cmd "acr purge --filter 'app:.*' --ago 30d --untagged --dry-run" /dev/null + +# Delete tags older than 30 days matching the regex, plus untagged manifests +az acr run --registry {registry} \ + --cmd "acr purge --filter 'app:.*' --ago 30d --untagged" /dev/null + +# Keep the 5 most recent tags regardless of age +az acr run --registry {registry} \ + --cmd "acr purge --filter 'app:.*' --ago 0d --keep 5 --untagged" /dev/null + +# Schedule as a nightly task +az acr task create --registry {registry} --name purge-old-images \ + --cmd "acr purge --filter 'app:.*' --ago 30d --untagged" \ + --context /dev/null --schedule "0 3 * * *" +``` + +`--filter` takes `repository:tag-regex` and can be repeated for multiple repos. + +## Lock Images + +Prevent overwrite or deletion of critical tags (e.g., released versions): + +```bash +# Read-only: cannot be overwritten or deleted +az acr repository update --name {registry} --image app:v1 --write-enabled false + +# Undeletable but still overwritable +az acr repository update --name {registry} --image app:v1 --delete-enabled false + +# Unlock +az acr repository update --name {registry} --image app:v1 --write-enabled true --delete-enabled true +``` + +## Retention Policy & Soft Delete + +Premium SKU: + +```bash +# Auto-delete untagged manifests after N days (0 = immediately) +az acr config retention update --registry {registry} \ + --status enabled --days 7 --type UntaggedManifests +az acr config retention show --registry {registry} + +# Soft delete (preview): recover deleted artifacts within the retention window +az acr config soft-delete update --registry {registry} --status enabled --days 7 +az acr repository list-deleted --name {registry} +``` + +## Artifact Cache (Pull-Through Cache) + +Cache upstream images (Docker Hub, MCR, GHCR, quay.io, ECR Public) in your registry — avoids rate limits and centralizes provenance: + +```bash +# Optional: credentials for authenticated upstream (secrets live in Key Vault) +az acr credential-set create --registry {registry} --name dockerhub-creds \ + --login-server docker.io \ + --username-id https://{vault}.vault.azure.net/secrets/dh-user \ + --password-id https://{vault}.vault.azure.net/secrets/dh-pass + +# Cache rule: docker.io/library/* -> {registry}.azurecr.io/dockerhub/* +az acr cache create --registry {registry} --name dockerhub-cache \ + --source-repo "docker.io/library/*" --target-repo "dockerhub/*" \ + --cred-set dockerhub-creds + +az acr cache list --registry {registry} --output table +``` + +Then `docker pull {registry}.azurecr.io/dockerhub/nginx:1.27` fetches through the cache. + +## Storage Usage + +```bash +# Consumed storage vs SKU quota (Basic 10 GB / Standard 100 GB / Premium 500 GB included) +az acr show-usage --name {registry} --output table +``` + +Layers are deduplicated and shared across repositories; `show-usage` reports actual billable storage. diff --git a/skills/azure-container-registry-cli/references/networking-and-geo.md b/skills/azure-container-registry-cli/references/networking-and-geo.md new file mode 100644 index 000000000..d2d29c8fd --- /dev/null +++ b/skills/azure-container-registry-cli/references/networking-and-geo.md @@ -0,0 +1,138 @@ +# Networking & Geo-Replication + +## Table of Contents +- [Geo-Replication](#geo-replication) +- [Zone Redundancy](#zone-redundancy) +- [Private Endpoints (Private Link)](#private-endpoints-private-link) +- [Public Network Rules](#public-network-rules) +- [Dedicated Data Endpoints](#dedicated-data-endpoints) +- [Connected Registry](#connected-registry) +- [Registry Transfer Pipelines](#registry-transfer-pipelines) + +All features on this page require the **Premium** SKU (except basic firewall behavior notes). + +--- + +## Geo-Replication + +One registry, one login server, images served from the nearest region: + +```bash +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 + +Set at creation time (registry or replica) in supported regions: + +```bash +az acr create --resource-group {rg} --name {registry} --sku Premium --zone-redundancy enabled +az acr replication create --registry {registry} --location westeurope --zone-redundancy enabled +``` + +## Private Endpoints (Private Link) + +```bash +# 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 in the VNet, or `az acr update --allow-trusted-services true` for trusted Azure services. + +## Public Network Rules + +Restrict public access to specific IPs instead of (or before) going fully private: + +```bash +# 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., ACR Tasks, Defender) through the firewall +az acr update --name {registry} --allow-trusted-services true +``` + +## 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: + +```bash +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: + +```bash +# 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`): + +```bash +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`). From 1851a92e94cb13388e36f3238cd1b3cbf41a2bb1 Mon Sep 17 00:00:00 2001 From: Adrien Clerbois Date: Mon, 27 Jul 2026 16:10:26 +0200 Subject: [PATCH 2/4] Address Copilot review: 2025 ACR changes (ABAC, zone redundancy, task network bypass) and secure credential handling --- skills/azure-container-registry-cli/SKILL.md | 6 +-- .../references/auth-and-security.md | 51 +++++++++++++++---- .../references/build-and-tasks.md | 12 ++++- .../references/networking-and-geo.md | 25 ++++++--- 4 files changed, 71 insertions(+), 23 deletions(-) diff --git a/skills/azure-container-registry-cli/SKILL.md b/skills/azure-container-registry-cli/SKILL.md index ab072d951..615430329 100644 --- a/skills/azure-container-registry-cli/SKILL.md +++ b/skills/azure-container-registry-cli/SKILL.md @@ -1,6 +1,6 @@ --- name: azure-container-registry-cli -description: Manage Azure Container Registry via the az acr CLI including registries, images, cloud builds, ACR Tasks, authentication, tokens, geo-replication, and networking. Use when working with ACR, az acr commands, pushing/importing/purging container images in Azure, or when the user mentions Azure Container Registry. +description: 'Manage Azure Container Registry via the az acr CLI including registries, images, cloud builds, ACR Tasks, authentication, tokens, geo-replication, and networking. Use when working with ACR, az acr commands, pushing/importing/purging container images in Azure, or when the user mentions Azure Container Registry.' --- # Azure Container Registry CLI @@ -49,8 +49,8 @@ az acr check-health --name {registry} --yes - **Prefer `az acr build` / ACR Tasks** over local `docker build` + `docker push`: builds run in Azure, work without a local daemon, and integrate with triggers. - **Prefer `az acr import`** to move images between registries: it is server-side, faster, and requires no local storage. -- **Never enable the admin user for production** — use Microsoft Entra identities (RBAC roles `AcrPull`/`AcrPush`), repository-scoped tokens, or managed identities. -- **Premium-only features**: geo-replication, private endpoints, tokens/scope maps, retention policies, connected registries, agent pools, zone redundancy. +- **Never enable the admin user for production** — use Microsoft Entra identities (RBAC roles `AcrPull`/`AcrPush`, or `Container Registry Repository Reader`/`Writer` on ABAC-enabled registries), repository-scoped tokens, or managed identities. +- **Premium-only features**: geo-replication, private endpoints, retention policies, connected registries, agent pools. (Repository-scoped tokens work in all tiers; zone redundancy is automatic in all tiers in supported regions.) ## CLI Structure diff --git a/skills/azure-container-registry-cli/references/auth-and-security.md b/skills/azure-container-registry-cli/references/auth-and-security.md index cc92e14c2..8b409776a 100644 --- a/skills/azure-container-registry-cli/references/auth-and-security.md +++ b/skills/azure-container-registry-cli/references/auth-and-security.md @@ -18,19 +18,27 @@ # Standard login — wires Docker/Podman credentials via your az login identity az acr login --name {registry} -# Without a Docker daemon: get an Entra access token for the registry -az acr login --name {registry} --expose-token -# Returns accessToken + loginServer; use with: -docker login {registry}.azurecr.io --username 00000000-0000-0000-0000-000000000000 --password-stdin +# Without a Docker daemon: get an Entra access token and pipe it to docker login +LOGIN_SERVER=$(az acr show --name {registry} --query loginServer --output tsv) +az acr login --name {registry} --expose-token --query accessToken --output tsv | \ + docker login $LOGIN_SERVER --username 00000000-0000-0000-0000-000000000000 --password-stdin ``` Notes: - `az acr login` tokens are valid for 3 hours; re-run on expiry. -- The full login server name is always `{registry}.azurecr.io` (lowercase). +- Resolve the login server with `az acr show --name {registry} --query loginServer --output tsv` rather than hardcoding it: it is usually `{registry}.azurecr.io`, but sovereign clouds use other suffixes and registries with a domain name label scope get a hash suffix. ## Microsoft Entra RBAC Roles -Built-in roles for data-plane access: +The applicable data-plane roles depend on the registry's **role assignment permissions mode** — check it first: + +```bash +az acr show --name {registry} --query roleAssignmentMode --output tsv +# LegacyRegistryPermissions -> use AcrPull/AcrPush/AcrDelete +# AbacRepositoryPermissions -> use Container Registry Repository Reader/Writer/Contributor +``` + +**Legacy mode (RBAC Registry Permissions):** | Role | Permissions | |---|---| @@ -40,6 +48,15 @@ Built-in roles for data-plane access: | `AcrImageSigner` | Sign images (content trust) | | `Contributor`/`Owner` | Full control-plane management + push/pull | +**ABAC-enabled mode (RBAC Registry + ABAC Repository Permissions):** `AcrPull`/`AcrPush`/`AcrDelete` are **not honored**, and `Owner`/`Contributor`/`Reader` grant control-plane only. Use instead: + +| Role | Permissions | +|---|---| +| `Container Registry Repository Reader` | Read images, tags, metadata (add ABAC conditions to scope to repositories) | +| `Container Registry Repository Writer` | Read + write/update | +| `Container Registry Repository Contributor` | Read + write + delete | +| `Container Registry Repository Catalog Lister` | List repositories (needed alongside the roles above) | + ```bash # Get the registry resource ID ACR_ID=$(az acr show --name {registry} --query id --output tsv) @@ -60,8 +77,8 @@ For CI/CD systems that cannot use OIDC/managed identity: ACR_ID=$(az acr show --name {registry} --query id --output tsv) az ad sp create-for-rbac --name {sp-name} --scopes $ACR_ID --role AcrPull -# Docker login with the SP -docker login {registry}.azurecr.io --username {appId} --password {password} +# Docker login with the SP — pipe the secret via stdin, never pass it as an argument +echo $SP_PASSWORD | docker login $LOGIN_SERVER --username {appId} --password-stdin ``` Prefer federated credentials (OIDC) over SP passwords in GitHub Actions / Azure DevOps when possible. @@ -95,9 +112,21 @@ az aks check-acr --name {cluster} --resource-group {rg} --acr {registry}.azurecr `--attach-acr` requires Owner or User Access Administrator on the registry. Cross-subscription attach works by passing the full ACR resource ID. +⚠️ `--attach-acr` assigns `AcrPull`, which is **not honored on ABAC-enabled registries** (`roleAssignmentMode` = `AbacRepositoryPermissions`). For those, assign the ABAC roles to the kubelet identity manually: + +```bash +ACR_ID=$(az acr show --name {registry} --query id --output tsv) +KUBELET_ID=$(az aks show --name {cluster} --resource-group {rg} \ + --query identityProfile.kubeletidentity.objectId --output tsv) +az role assignment create --assignee $KUBELET_ID --scope $ACR_ID \ + --role "Container Registry Repository Reader" +az role assignment create --assignee $KUBELET_ID --scope $ACR_ID \ + --role "Container Registry Repository Catalog Lister" +``` + ## Repository-Scoped Tokens -Premium SKU. Fine-grained, non-Entra credentials (e.g., external partners, IoT devices): +Available in all service tiers. Fine-grained, non-Entra credentials (e.g., external partners, IoT devices): ```bash # 1. Create a scope map (actions: content/read, content/write, content/delete, metadata/read, metadata/write) @@ -111,8 +140,8 @@ az acr token create --name {token} --registry {registry} --scope-map {scope-map} # 3. Generate/rotate passwords (up to 2, optional expiry) az acr token credential generate --name {token} --registry {registry} --password1 --expiration-in-days 30 -# Login with the token -docker login {registry}.azurecr.io --username {token} --password {token-password} +# Login with the token — pipe the password via stdin, never pass it as an argument +echo $TOKEN_PWD | docker login $LOGIN_SERVER --username {token} --password-stdin # Disable or delete az acr token update --name {token} --registry {registry} --status disabled diff --git a/skills/azure-container-registry-cli/references/build-and-tasks.md b/skills/azure-container-registry-cli/references/build-and-tasks.md index 5070fc64c..f97395e69 100644 --- a/skills/azure-container-registry-cli/references/build-and-tasks.md +++ b/skills/azure-container-registry-cli/references/build-and-tasks.md @@ -24,8 +24,10 @@ az acr build --registry {registry} --image app:v1 \ --build-arg VERSION=1.2.3 \ --platform linux/amd64 . -# Multi-arch: run one build per platform (linux/amd64, linux/arm64, windows/amd64) +# Cross-platform: each build produces ONE single-architecture image for the target platform az acr build --registry {registry} --image app:v1-arm64 --platform linux/arm64 . +# For a true multi-arch image, build once per platform under arch-specific tags, then +# assemble and push a manifest list (docker manifest create/push, or docker buildx locally) # Build directly from a Git repo (no local clone) az acr build --registry {registry} --image app:v1 https://github.com/{org}/{repo}.git#{branch}:{folder} @@ -77,6 +79,8 @@ az acr task delete --registry {registry} --name build-app --yes Useful run variables for `--image`: `{{.Run.ID}}`, `{{.Run.Commit}}`, `{{.Run.Branch}}`, `{{.Run.Date}}`. +⚠️ On **ABAC-enabled registries** (`roleAssignmentMode` = `AbacRepositoryPermissions`), tasks and quick builds/runs have no default access to the source registry. Pass `--source-acr-auth-id [caller]` to `az acr build`/`az acr run`, and `--source-acr-auth-id [system]` (or a user-assigned identity resource ID) to `az acr task create`/`update`, then grant that identity the `Container Registry Repository ...` roles. + ## Triggers ```bash @@ -129,6 +133,12 @@ Premium SKU. Dedicated task compute — required when the registry is behind a f ```bash az acr agentpool create --registry {registry} --name pool1 --tier S2 # S1/S2/S3/I6 + +# For the firewall/VNet scenario, the pool MUST be attached to a subnet that can +# reach the registry's private endpoint — without --subnet-id it runs outside the VNet +az acr agentpool create --registry {registry} --name pool1 --tier S2 \ + --subnet-id /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{vnet}/subnets/{subnet} + az acr agentpool list --registry {registry} --output table # Target the pool diff --git a/skills/azure-container-registry-cli/references/networking-and-geo.md b/skills/azure-container-registry-cli/references/networking-and-geo.md index d2d29c8fd..5394ea208 100644 --- a/skills/azure-container-registry-cli/references/networking-and-geo.md +++ b/skills/azure-container-registry-cli/references/networking-and-geo.md @@ -9,7 +9,7 @@ - [Connected Registry](#connected-registry) - [Registry Transfer Pipelines](#registry-transfer-pipelines) -All features on this page require the **Premium** SKU (except basic firewall behavior notes). +Geo-replication, private endpoints, connected registries, and transfer pipelines require the **Premium** SKU. Zone redundancy is automatic in every tier. --- @@ -31,12 +31,9 @@ Pushes replicate automatically; clients keep pulling `{registry}.azurecr.io` and ## Zone Redundancy -Set at creation time (registry or replica) in supported regions: +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. -```bash -az acr create --resource-group {rg} --name {registry} --sku Premium --zone-redundancy enabled -az acr replication create --registry {registry} --location westeurope --zone-redundancy enabled -``` +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) @@ -66,7 +63,7 @@ az acr private-endpoint-connection approve --registry-name {registry} --name {co 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 in the VNet, or `az acr update --allow-trusted-services true` for trusted Azure services. +- 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 @@ -79,10 +76,22 @@ 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., ACR Tasks, Defender) through the firewall +# 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: + +```bash +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](https://github.com/azure/acr-cli). 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: From 50991e6a0855335a37ac8e6900c40686ee532486 Mon Sep 17 00:00:00 2001 From: Adrien Clerbois Date: Tue, 28 Jul 2026 12:15:17 +0200 Subject: [PATCH 3/4] Add ACI (Azure Container Instances) to codespell ignore list --- .codespellrc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.codespellrc b/.codespellrc index d38ea35d8..7059de5b6 100644 --- a/.codespellrc +++ b/.codespellrc @@ -62,7 +62,9 @@ # Vally/vally - Name of product -ignore-words-list = numer,wit,aks,edn,ser,ois,gir,rouge,categor,aline,ative,afterall,deques,dateA,dateB,TE,FillIn,alle,vai,LOD,InOut,pixelX,aNULL,Wee,Sherif,queston,extenions,Vertexes,nin,FO,CAF,Parth,ans,gud,Vally,vally +# ACI - Azure Container Instances abbreviation + +ignore-words-list = numer,wit,aks,edn,ser,ois,gir,rouge,categor,aline,ative,afterall,deques,dateA,dateB,TE,FillIn,alle,vai,LOD,InOut,pixelX,aNULL,Wee,Sherif,queston,extenions,Vertexes,nin,FO,CAF,Parth,ans,gud,Vally,vally,ACI # Skip certain files and directories # *.tm7 - MTM DataContract exports; embedded base64 icon blobs trigger false positives From 569215d6b0a07f2f27a04e27d1299dbd6cb8c25b Mon Sep 17 00:00:00 2001 From: Adrien Clerbois Date: Tue, 28 Jul 2026 12:24:21 +0200 Subject: [PATCH 4/4] Address second Copilot review wave: DCT deprecation, purge --untagged caveat, soft-delete tiers, Catalog Lister scope, secret quoting --- .../references/auth-and-security.md | 26 +++++++++---------- .../references/build-and-tasks.md | 4 +-- .../references/images-and-artifacts.md | 9 ++++--- .../references/networking-and-geo.md | 2 +- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/skills/azure-container-registry-cli/references/auth-and-security.md b/skills/azure-container-registry-cli/references/auth-and-security.md index 8b409776a..4c9985c3e 100644 --- a/skills/azure-container-registry-cli/references/auth-and-security.md +++ b/skills/azure-container-registry-cli/references/auth-and-security.md @@ -55,7 +55,7 @@ az acr show --name {registry} --query roleAssignmentMode --output tsv | `Container Registry Repository Reader` | Read images, tags, metadata (add ABAC conditions to scope to repositories) | | `Container Registry Repository Writer` | Read + write/update | | `Container Registry Repository Contributor` | Read + write + delete | -| `Container Registry Repository Catalog Lister` | List repositories (needed alongside the roles above) | +| `Container Registry Repository Catalog Lister` | List repositories — assign only when the identity must enumerate the catalog (e.g., `az acr repository list`); not needed for pull/push of known repositories | ```bash # Get the registry resource ID @@ -78,7 +78,8 @@ ACR_ID=$(az acr show --name {registry} --query id --output tsv) az ad sp create-for-rbac --name {sp-name} --scopes $ACR_ID --role AcrPull # Docker login with the SP — pipe the secret via stdin, never pass it as an argument -echo $SP_PASSWORD | docker login $LOGIN_SERVER --username {appId} --password-stdin +# (printf with a quoted variable preserves whitespace/glob characters exactly) +printf '%s' "$SP_PASSWORD" | docker login $LOGIN_SERVER --username {appId} --password-stdin ``` Prefer federated credentials (OIDC) over SP passwords in GitHub Actions / Azure DevOps when possible. @@ -120,8 +121,8 @@ KUBELET_ID=$(az aks show --name {cluster} --resource-group {rg} \ --query identityProfile.kubeletidentity.objectId --output tsv) az role assignment create --assignee $KUBELET_ID --scope $ACR_ID \ --role "Container Registry Repository Reader" -az role assignment create --assignee $KUBELET_ID --scope $ACR_ID \ - --role "Container Registry Repository Catalog Lister" +# "Container Registry Repository Catalog Lister" is NOT needed for pulls — +# only add it if the identity must list repositories ``` ## Repository-Scoped Tokens @@ -141,7 +142,7 @@ az acr token create --name {token} --registry {registry} --scope-map {scope-map} az acr token credential generate --name {token} --registry {registry} --password1 --expiration-in-days 30 # Login with the token — pipe the password via stdin, never pass it as an argument -echo $TOKEN_PWD | docker login $LOGIN_SERVER --username {token} --password-stdin +printf '%s' "$TOKEN_PWD" | docker login $LOGIN_SERVER --username {token} --password-stdin # Disable or delete az acr token update --name {token} --registry {registry} --status disabled @@ -160,15 +161,14 @@ az acr credential renew --name {registry} --password-name password2 # rotate Legitimate uses: quick local tests, services that only accept username/password and cannot use tokens. -## Content Trust +## Content Trust (deprecated) -```bash -# Enable Docker Content Trust support (Premium) -az acr config content-trust update --registry {registry} --status enabled +Docker Content Trust (DCT) is being retired: **since May 31, 2026 it cannot be enabled on new registries** (or on registries that never enabled it), and it will be removed entirely on March 31, 2028. Do not set up DCT — sign images with **Notation (Notary Project)** and store signatures as OCI artifacts instead; see "Transition from Docker Content Trust to Notary Project" in the ACR docs. -# Client side: push signed images -export DOCKER_CONTENT_TRUST=1 -docker push {registry}.azurecr.io/app:v1 +```bash +# Registries with legacy DCT only — inspect or disable the existing configuration +az acr config content-trust show --registry {registry} +az acr config content-trust update --registry {registry} --status disabled ``` -Signers need `AcrImageSigner` in addition to `AcrPush`. For new projects prefer Notation/ORAS-based signing over Docker Content Trust. +Legacy DCT signers needed `AcrImageSigner` in addition to `AcrPush`. diff --git a/skills/azure-container-registry-cli/references/build-and-tasks.md b/skills/azure-container-registry-cli/references/build-and-tasks.md index f97395e69..84430cce4 100644 --- a/skills/azure-container-registry-cli/references/build-and-tasks.md +++ b/skills/azure-container-registry-cli/references/build-and-tasks.md @@ -79,7 +79,7 @@ az acr task delete --registry {registry} --name build-app --yes Useful run variables for `--image`: `{{.Run.ID}}`, `{{.Run.Commit}}`, `{{.Run.Branch}}`, `{{.Run.Date}}`. -⚠️ On **ABAC-enabled registries** (`roleAssignmentMode` = `AbacRepositoryPermissions`), tasks and quick builds/runs have no default access to the source registry. Pass `--source-acr-auth-id [caller]` to `az acr build`/`az acr run`, and `--source-acr-auth-id [system]` (or a user-assigned identity resource ID) to `az acr task create`/`update`, then grant that identity the `Container Registry Repository ...` roles. +⚠️ On **ABAC-enabled registries** (`roleAssignmentMode` = `AbacRepositoryPermissions`), tasks and quick builds/runs have no default access to the source registry. Pass `--source-acr-auth-id [caller]` to `az acr build`/`az acr run`, and `--source-acr-auth-id [system]` (or a user-assigned identity resource ID) to `az acr task create`/`update`, then grant that identity the `Container Registry Repository ...` roles. Ensure the task actually has that identity — add `--assign-identity [system]` at creation, or run `az acr task identity assign` on an existing task, before referencing it. ## Triggers @@ -129,7 +129,7 @@ az acr task create --registry {registry} --name build-test-push \ ## Agent Pools -Premium SKU. Dedicated task compute — required when the registry is behind a firewall/VNet, or for more CPU: +Premium SKU. Dedicated task compute — for more CPU, or one of the two supported ways to run tasks against a network-restricted registry (the other being trusted services + the task network bypass policy, see `networking-and-geo.md`): ```bash az acr agentpool create --registry {registry} --name pool1 --tier S2 # S1/S2/S3/I6 diff --git a/skills/azure-container-registry-cli/references/images-and-artifacts.md b/skills/azure-container-registry-cli/references/images-and-artifacts.md index b10cde174..554e7457b 100644 --- a/skills/azure-container-registry-cli/references/images-and-artifacts.md +++ b/skills/azure-container-registry-cli/references/images-and-artifacts.md @@ -106,6 +106,8 @@ az acr task create --registry {registry} --name purge-old-images \ `--filter` takes `repository:tag-regex` and can be repeated for multiple repos. +⚠️ `--untagged` ignores `--ago`: it deletes **every** untagged manifest, including ones created moments ago (mid-push images, referrer artifacts). Omit `--untagged` if recent untagged manifests must survive — the age cutoff only applies to tagged images matched by `--filter`. + ## Lock Images Prevent overwrite or deletion of critical tags (e.g., released versions): @@ -123,17 +125,18 @@ az acr repository update --name {registry} --image app:v1 --write-enabled true - ## Retention Policy & Soft Delete -Premium SKU: +Two distinct policies that **cannot be enabled at the same time**. Retention policy requires **Premium**; soft delete (preview) is available in **all tiers** but doesn't support geo-replicated or artifact-cache-enabled registries. ```bash -# Auto-delete untagged manifests after N days (0 = immediately) +# Retention policy (Premium): auto-delete untagged manifests after N days (0 = immediately) az acr config retention update --registry {registry} \ --status enabled --days 7 --type UntaggedManifests az acr config retention show --registry {registry} -# Soft delete (preview): recover deleted artifacts within the retention window +# Soft delete (preview, all tiers): recover deleted artifacts within 1-90 days az acr config soft-delete update --registry {registry} --status enabled --days 7 az acr repository list-deleted --name {registry} +az acr manifest restore --registry {registry} --name app:v1 ``` ## Artifact Cache (Pull-Through Cache) diff --git a/skills/azure-container-registry-cli/references/networking-and-geo.md b/skills/azure-container-registry-cli/references/networking-and-geo.md index 5394ea208..86595dacd 100644 --- a/skills/azure-container-registry-cli/references/networking-and-geo.md +++ b/skills/azure-container-registry-cli/references/networking-and-geo.md @@ -9,7 +9,7 @@ - [Connected Registry](#connected-registry) - [Registry Transfer Pipelines](#registry-transfer-pipelines) -Geo-replication, private endpoints, connected registries, and transfer pipelines require the **Premium** SKU. Zone redundancy is automatic in every tier. +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. ---