Files
awesome-copilot/skills/azure-container-registry-cli/references/auth-and-security.md
T
Adrien Clerbois 45305f1602 Add azure-container-registry-cli skill (#2450)
* 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>
2026-07-30 11:52:42 +10:00

175 lines
7.5 KiB
Markdown

# 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 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.
- 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
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 |
|---|---|
| `AcrPull` | Pull images |
| `AcrPush` | Pull + push images |
| `AcrDelete` | Delete images |
| `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 — 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
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 — pipe the secret via stdin, never pass it as an argument
# (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.
## 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.
⚠️ `--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"
# "Container Registry Repository Catalog Lister" is NOT needed for pulls —
# only add it if the identity must list repositories
```
## Repository-Scoped Tokens
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)
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 — pipe the password via stdin, never pass it as an argument
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
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 (deprecated)
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.
```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
```
Legacy DCT signers needed `AcrImageSigner` in addition to `AcrPush`.