How to Push Images to Azure Container Registry

A developer on a payments team once pinged me because his build kept failing with “unauthorized: authentication required.” He had copied a registry password from an old wiki page, and someone had since rotated it. Worse, the old password was also sitting in three pipeline files. We fixed the build in ten minutes. Cleaning up the leaked credential took the rest of the week.

Learning how to push images to Azure Container Registry is easy. Doing it without shared passwords, public exposure, or mystery tags is where the real work is. The push itself is only four commands. The decisions around identity, networking, and automation decide whether your registry stays trustworthy.

This guide shows you how to push images with Docker, with ACR Tasks, and from a pipeline. You will use Microsoft Entra ID instead of stored passwords, handle private networking, and troubleshoot the errors that stop most first-time pushes.

What You Need Before You Push an Image

Azure Container Registry (ACR) is a managed private registry for container images. A container image is a packaged application and its dependencies. Before you push anything, you need four things.

  • An existing registry. You need its name and its login server, which is <registry-name>.azurecr.io. If you are still choosing a tier, remember that private endpoints and IP rules need Premium.
  • The Azure CLI. Install it with our guide for installing Azure CLI on Windows, or read what the Azure CLI is if it is new to you.
  • Docker or another build tool. Docker Desktop or the Docker engine builds images locally. If you cannot install Docker, you can build in Azure instead, which I cover below.
  • The right permission. Your identity needs the AcrPush role on the registry. Reader or Contributor on the Azure resource does not let you push images.

That last point catches many people. Role-based access control (RBAC) assigns permissions through roles instead of broad administrator access. Azure splits “manage the registry resource” from “push and pull images” on purpose. Our overview of Azure RBAC explains the model.

Decide Where the Image Will Run

Your runtime affects how you tag and authenticate. An image headed for App Service needs a pull identity on the web app. An image for a cluster needs the cluster’s kubelet identity to hold AcrPull. If you have not picked a runtime yet, compare Web App for Containers vs AKS vs Container Instances first.

Pro Tip: In my experience, I confirm the runtime before I name repositories. Renaming repositories later means retagging images and editing every deployment that references them.

How to Push Images to Azure Container Registry With Docker

This is the classic workflow. It works from a laptop, a build server, or a CI agent with Docker installed.

Step 1: Sign In to Azure and the Registry

az login
az acr login --name <registry-name>

The az login command signs you in with Microsoft Entra ID, including multifactor authentication. The az acr login command then exchanges that sign-in for a short-lived registry token and hands it to Docker, so you never type a password. The token typically lasts about three hours, so long sessions need a fresh login. If sign-in options are unfamiliar, read our Azure CLI login guide.

If az acr login cannot reach the Docker daemon, such as on some remote hosts, request the token directly:

az acr login --name <registry-name> --expose-token --output tsv --query accessToken | \
docker login <registry-name>.azurecr.io \
--username 00000000-0000-0000-0000-000000000000 \
--password-stdin

The --expose-token parameter returns the access token instead of configuring Docker. Piping it into docker login with --password-stdin keeps the token out of your shell history and process list. The all-zero username is the documented placeholder that tells ACR you are using a token. Never paste tokens into scripts or chat messages.

Step 2: Build and Tag the Image

docker build -t employee-portal:1.0.0 .
docker tag employee-portal:1.0.0 <registry-name>.azurecr.io/employee-portal:1.0.0

The docker build command creates the image from the Dockerfile in the current folder. The -t flag gives it a local name and tag. The docker tag command adds a second name that includes the registry’s login server. That prefix is how Docker knows where to push. A full image reference looks like <login-server>/<repository>:<tag>, and the repository is a named group of related image versions.

Step 3: Push and Verify

docker push <registry-name>.azurecr.io/employee-portal:1.0.0
az acr repository show-tags \
--name <registry-name> \
--repository employee-portal \
--orderby time_desc \
--output table

The docker push command uploads the image layers. Layers that already exist in the registry are skipped, which makes later pushes much faster. The show-tags command confirms the tag arrived, and --orderby time_desc lists the newest first.

Azure PowerShell Option

Windows administrators who prefer PowerShell can use the Az module for the login step.

$RegistryName = "<registry-name>"
$ImageName = "employee-portal:1.0.0"

Connect-AzAccount
Connect-AzContainerRegistry -Name $RegistryName

docker tag $ImageName "$RegistryName.azurecr.io/$ImageName"
docker push "$RegistryName.azurecr.io/$ImageName"

The Connect-AzAccount cmdlet signs you in to Azure. The Connect-AzContainerRegistry cmdlet authenticates Docker to the registry named in $RegistryName. The remaining lines tag and push, exactly like the CLI flow. Not sure which tool to choose? Our comparison of Azure PowerShell vs Azure CLI lays out the trade-offs.

Pro Tip: I always use an explicit version or build ID tag and never only latest. A moving latest tag makes rollbacks guesswork, and I have watched a bad image reach production because two teams both pushed “latest.”

Build and Push Without Docker Using ACR Tasks

Sometimes you cannot or should not run Docker locally. Locked-down laptops, Windows servers without virtualization, and shared build agents are common examples. ACR Tasks builds images inside Azure and pushes them to your registry in one step.

az acr build \
--registry <registry-name> \
--image employee-portal:1.0.1 \
.

The --registry parameter names the target registry. The --image parameter sets the repository and tag. The trailing . is the build context, which is the folder of source files uploaded to Azure. ACR builds the image and pushes it automatically, so no separate docker push is needed. The build log streams back to your terminal.

This approach has two benefits. First, the build runs next to the registry, so layer uploads are fast and do not depend on your office network. Second, build agents no longer need a Docker daemon, which removes a privileged component from your CI fleet. The trade-off is that ACR Tasks compute is billed by the second, so large builds add cost.

Import Trusted Base Images

Many teams also copy approved base images into their own registry so builds never depend on an outside service at build time.

az acr import \
--name <registry-name> \
--source mcr.microsoft.com/dotnet/aspnet:8.0 \
--image base/aspnet:8.0

The az acr import command copies the image directly between registries without pulling it to your machine. The --source parameter identifies the original image. The --image parameter sets the new repository path. Your Dockerfiles can then reference <registry-name>.azurecr.io/base/aspnet:8.0, which gives you one controlled, scanned source for base layers.

Pro Tip: I once debugged a build outage that came from an upstream registry rate limit during a busy morning. Importing base images into ACR on a schedule removed that dependency completely.

Authenticate Without Shared Passwords

Every unnecessary shared secret is a future incident. ACR supports several sign-in methods, and the choice should follow the caller.

CallerBest methodWhy
Developer on a laptopaz acr login with Entra IDMFA, per-user audit trail
App Service, AKS, Container Apps pulling imagesManaged identity with AcrPullNo secret to store or rotate
Azure DevOps or GitHub pipelineWorkload identity federation or service connectionShort-lived tokens
Tool outside AzureService principal with a narrow roleIndependent identity, but needs secret handling
Anyone, everAdmin userAvoid it

The registry admin user is a single shared account with full push and pull rights. Every caller appears as the same person in logs, and rotating its password breaks everyone at once. Keep it disabled.

Grant Push Access to a Group

ACR_ID=$(az acr show --name <registry-name> --query id --output tsv)

az role assignment create \
--assignee <entra-group-object-id> \
--role AcrPush \
--scope $ACR_ID

The first line saves the registry’s resource ID. The az role assignment create command then gives the group the AcrPush role, limited to this single registry by --scope. That is least privilege: the group can push and pull images, but cannot delete the registry or change its network settings. Assigning to a group means joiners and leavers are handled in Microsoft Entra ID and never touch the registry.

Use Managed Identities and Service Principals Correctly

A managed identity is an identity Azure creates and rotates for a resource, so the code never holds a secret. If your build runs on an Azure VM or agent with an identity, sign in like this:

az login --identity
az acr login --name <registry-name>

The --identity flag signs in with the VM’s managed identity. See our article on managed identities in Azure for system-assigned and user-assigned types. For tools outside Azure, follow our