Introduction
When automating administration tasks via scripts in Azure DevOps in the past I would have commonly used the Azure DevOps REST API. However, today I tend to favour the Azure DevOps CLI. The reason for this is that the CLI wrappers the REST API in such a way that it is easier to use and more consistent.
One of the most noticeable advantages is in the area of authentication. The CLI supports a number of authentication methods that are not directly available to the REST API. In this post, I will explore the options available to authenticate the Azure DevOps CLI.
Authentication Options
Note: the Azure CLI has a login command az login
, but so does the Azure DevOps extension az devops login
, we have the option to use either depending on the authentication method picked
Azure CLI Personal Access Token (PAT)
PATs have historically been the usual means to authenticate with Azure DevOps . They are still perfectly valid, and the easiest way to authenticate for command line usage. However, it is worth noting that Microsoft are now recommending a move away from PATs.
The basic command to use a PAT is az devops login
, when this is run you will be prompted for your PAT.
A script can build on this authentication mechanism and allow the PAT to be passed into the script by echoing it into the az
command.
echo "<my-pat>" | az devops login --organization "https://dev.azure.com/myorg
Interactive Login using Entra ID
An alternative to using a PAT is to login to the Azure CLI using your corporate ID. This can be done outside of any script that executes as series of CLI commands, by using the az login
command prior to running the script, or making it the first item in the script.
This will launch a browser allowing you to authenticate via Entra ID using your corporate ID. Your session will be valid for a period of time, and you can use any az
commands. The problem is that this is not suitable for a script that needs to run unattended, as it requires a user to be present to authenticate.
Using a Service Principle
A Service Principle is an application registration within Entra ID.
In Azure DevOps, a Service Principle can be granted access to an Azure DevOps Organisation and Project as you would a user account i.e. the Service Account can be granted a license and given permissions inside a project.
You can create a Service Principle using the command
az ad sp create-for-rbac --name myServicePrincipalName1 --role reader --scopes /subscriptions/00000000-0000-0000-0000-000000000000
Note: The Service Principle must have at least the role of ‘reader’ in the Azure Subscription associated with the Entra ID
When the above command is run, the result will be block of JSON including an appId, password and tenantID. These values should be stored securely
Once the Service Principle has been created you grant it permissions to the Azure DevOps Organisation and Projects as needed.
Finally, using the securely stored values, you can now authenticate with the Azure ClI using the form
az login --service-principal -u <appID> -p <password> --tenant <tenantid>
Unlike the interactive login, if you used this mechanism you have the option to pass these values into a script as parameters. So can be used for unattended scripts.
Managed Identity
The final option is to use an Azure Managed Identity.
A Managed Identity is created as a resource in Azure. Like a Service Principle, a Managed Identity can be granted a license and permissions in Azure DevOps.
To login with a Managed Identity you can use the command
az login --identity
This works because the Managed Identity must be associated with the Azure VM you are running the az command on.
The need to be on an Azure VM is the limitation of Managed Identities. They are only usable inside and Azure hosted resource, so are not appropriate to your needs if you wish to run your script, that uses the Azure CLI, from locations outside Azure.
So what do I use?
My most common use-case is to run a script that uses the AZ CLI from within an Azure DevOps Pipeline.
If my script needs permissions beyond Azure DevOps, I will probably use a Service Principle. This is because I can grant the Service Principle permissions to other resources in Azure, and I can pass the Service Principle values into the script as parameters from secret Azure DevOps Pipeline variables.
However, my scripts commonly only need to interact with Azure DevOps, and in this case I just use the Build Agent token as a PAT. This is because it avoids the need to set anything up, you can easily pass the token into the script as an environment variable.
trigger: none
pool:
vmImage: ubuntu-latest
steps:
- task: PowerShell@2
displayName: 'Increment PBI count'
inputs:
targetType: 'inline'
pwsh: true
script: |
# I don't need to call az login as it done automaticallly
az devops ....
env:
AZURE_DEVOPS_EXT_PAT: $(System.AccessToken)