Skip to content

Azure Container Registry

ACR is a first-class AAD citizen: every form of authentication ultimately exchanges into an ACR-scoped AAD access token, then exchanges that for a registry refresh token. HarborGuard supports the four practical paths.

Auth options

MethodWhen to useHarborGuard fields
Service principal (client ID + secret)Cloud scan, or sensor outside AzureUsername = client ID (UUID), Password = client secret
Managed identitySensor on Azure VM / AKS / Container AppsNone — sensor uses IMDS
AAD user / device-code tokenManual / interactive — short-livedUsername 00000000-0000-0000-0000-000000000000, Password = AAD access token for https://<registry>.azurecr.io
Admin user (registry-level)Quick test only; disabled by policy in most prod tenantsUsername + Password from the ACR admin tab

The wizard auto-detects ACR from the *.azurecr.io suffix.

Add the registry

  1. Registries → Connect Registry.
  2. Registry URLmyregistry.azurecr.io (no path).
  3. The wizard shows Azure ACR Detected.
  4. Cloud: enter the service principal's client ID + secret.
  5. Save. The tenant ID isn't entered separately — it's discovered from the AAD challenge returned by /v2/.

Required role assignments

Assign on the registry resource (or a higher scope):

RolePurpose
AcrPullRead images. Required.
AcrDeleteNot needed; HarborGuard never deletes
AcrPushNot needed
Reader (on the resource group)Optional — only if you want HarborGuard's UI to show resource metadata
az role assignment create \
  --assignee <client-id> \
  --role AcrPull \
  --scope /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.ContainerRegistry/registries/<registry>

For managed identity, the same role assignment goes to the identity's principal ID.

Push-event sync

ACR Premium SKU emits Event Grid events on every push. Standard and Basic SKUs do not.

  1. In the registry's Events blade, create a subscription with event type ImagePushed.
  2. Endpoint: https://<your-harborguard-host>/api/webhooks/acr.
  3. Set the registry's schedule to on_push.

Geo-replicated registries emit one event per replica push — HarborGuard de-duplicates by digest within a 60-second window.

Common pitfalls

  • AcrPull is not Reader. A principal with Reader on the resource group cannot pull images. The two roles are independent.
  • Tag immutability. If you've enabled the tagImmutability policy, re-pushing the same tag fails — HarborGuard's "rescan latest" only works if the digest changed or the tag was rebuilt to a new digest.
  • Content trust / signature requirements. A registry policy that requires signed images blocks anonymous catalog reads but does not affect authenticated pulls. If you see 403s on /v2/_catalog only, content trust is the culprit.
  • Geo-replication. Each replica advertises the same registry name. A sensor in eastus with network restrictions targeting eastus will fail if DNS resolves to the westeurope replica — pin the replica via Azure DNS or use Private Link.
  • Admin user disabled by policy. Microsoft.ContainerRegistry/registries/disableAdminUser is a common Policy assignment. If admin user was your plan, you need a service principal instead.

Troubleshooting

SymptomLikely cause
Test returns 401 with valid client ID + secretThe service principal's client secret has expired (1- or 2-year default)
Test returns 403 after successful authMissing AcrPull role assignment
Catalog enumerates but specific repos 404Repository-scoped tokens issued via tokens resource — HarborGuard expects an account-scoped principal
Push events arrive but scans don't runSchedule is still daily — flip it to on_push after the Event Grid subscription is verified
Managed identity works locally, fails on AKSaad-pod-identity / Workload Identity isn't bound to the sensor pod's service account

On this page