mirror of
https://github.com/github/awesome-copilot.git
synced 2026-08-03 16:02:33 +00:00
45305f1602
* 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>
175 lines
7.5 KiB
Markdown
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`.
|