Azure Service Principles Names (SPN) with Azure Container Registry (ACR) are fairly easy to implement as part of your CI/CD pipeline.

Instead of handing out a generic admin account, why not have your ACR a bit more secured?!

Your private container registry is part of your CI/CD pipeline DNA, there is no question about it. What I found interesting is that other than username and password for granular access, not many are taking RBAC into account.

Disclaimer: I consider this post as an add-on to the original post, Azure Container Registry authentication with service principals from the official Azure docs website. The reason for this post is to try giving a bit more context and screenshots as I think it will encourage more people to secure their ACR.

The “why using it?” section in the original post is summarized pretty well. In a nutshell, when you incorporating RBAC using SPNs, you are providing “separation of duties” for all that is touching your registry. 

So for example, when you need the build server to push & pull Docker images to the registry while your web application only need to pull the latest build image, all in an automated unattained fashion, scoped SPNs can come very handy – This is what we call headless scenarios.

To do that, first, let’s create a couple of Azure SPNs, one for the push and another one for the pull functionality.  You can find the complete list of ACR permissions in the official GitHub repo. One thing to note here is that allowing the SPN to push images will grant pulling as well. 

For the purpose of this post, I modified the original script that is in the Azure docs website so it will create both pull and push SPNs in a single run. I also removed the “http://” header in the actual SPN creation command (line 18) to get the SPN name the way I want it, you will see in a sec.

As a bonus so you won’t have to remember the output or leave you terminal open, I’ve added a bunch of tee commands at the end. 

Go ahead and run the script. The only thing you need before that is the Azure CLI installed (or you can run it in Azure Cloud Shell) and an ACR up & running. 


# Modify for your environment.
# ACR_NAME: The name of your Azure Container Registry
# SERVICE_PRINCIPAL_NAME: Must be unique within your AD tenant
ACR_NAME="YOUR Azure Container Registry Name"

# Obtain the full registry ID for subsequent command args
ACR_REGISTRY_ID=$(az acr show --name $ACR_NAME --query id --output tsv)

# Create the service principal with rights scoped to the registry.
# Default permissions are for docker pull access. Modify the '--role'
# argument value as desired:
# acrpull:     pull only
# acrpush:     push and pull
# owner:       push, pull, and assign roles
PULL_SP_PASSWD=$(az ad sp create-for-rbac --name $PULL_SERVICE_PRINCIPAL_NAME --scopes $ACR_REGISTRY_ID --role acrpull --query password --output tsv)
PULL_SP_APP_ID=$(az ad sp show --id http://$PULL_SERVICE_PRINCIPAL_NAME --query appId --output tsv)
PUSH_SP_PASSWD=$(az ad sp create-for-rbac --name $PUSH_SERVICE_PRINCIPAL_NAME --scopes $ACR_REGISTRY_ID --role acrpush --query password --output tsv)
PUSH_SP_APP_ID=$(az ad sp show --id http://$PUSH_SERVICE_PRINCIPAL_NAME --query appId --output tsv)

# Output the service principal's credentials; use these in your services and
# applications to authenticate to the container registry.

echo "ACR Pull Service principal ID: $PULL_SP_APP_ID" | tee -a acr-spn.txt
echo "ACR Pull Service principal password: $PULL_SP_PASSWD" | tee -a acr-spn.txt
echo ""
echo "ACR Push Service principal ID: $PUSH_SP_APP_ID" | tee -a acr-spn.txt
echo "ACR Push Service principal password: $PUSH_SP_PASSWD" | tee -a acr-spn.txt

As you can see, after few seconds, two new SPNs has been generated – one for pull and one for push. Let’s verify and see it in ACR. It will in the Access Control section under the Role Assignment tab. 

To test those SPN RBAC functionality and to keep things light, I will be using the alpine Docker image that I already pulled locally. 

First, let’s test the push SPN (which will give us the option to pull images as well). Using the push/pull SPN, login to your ACR with the following command.
docker login <YOUR ACR>  -u <SP_APP_ID> -p <SP_PASSWD> 

Now that we are in, tag the image so you can push it to ACR. Once done, see if you can push to your ACR and see the image in your repository. 

To test if you can pull the image locally, delete the tagged image and pull it from ACR. 

As you can see, this SPN can push and pull Docker images from your registry, same as you CI build platform will have to be able to do. 
Now, let’s login to ACR with the pull SPN and test it (prior to that, I did some housecleaning and deleted the tagged image again). 

Run the docker pull following by the docker push command.

As you can see, pulling the image is working as expected but pushing it with the pull SPN is not authorized. This can come handy when needing your deployment platform (as part of your CD pipeline) to have restricted access to ACR or even if you just want to provide someone these SPN credentials so he can pull your ACR images without being able to push it back to you.

Enjoy securing your ACR 🙂


Please enter your comment!
Please enter your name here