Life's random bits By b1thunt3r (aka Ishan Jain)…
Register Self-Hosted Azure DevOps Agent using Service Principal

Register Self-Hosted Azure DevOps Agent using Service Principal

Ishan jain
Personal Access Tokens (PAT) are evil, avoid them. Use Service Principal instead.

I have a "slight" dislike for Personal Access Tokens (PATs). My dislike comes from un-manageability of them. In Azure DevOps (ADO), PATs are created by each user, there is no way to create them on the organization or project level. Then worst part is, even if you disable an user in ADO, PATs are still active. So, from security stand point PATs are EVIL.

With version 3.227.1 of Azure Pipeline Agent, we are able to use Service Principal as authentication method.

What did make it a bit harder to use was, it is not documented in any way.

I did figure out 3 ways you can use Service Principal for registering an Agent.

Prerequisites

Method 1 - Service Principal as Authentication Method

./config.sh --auth sp \
--url <org_url> \
--clientid <client_id> \
--tenantid <tenant_id> \
--clientsecret <client_secret> \
--agent <agent_name> \
--pool <agent_pool_name> \
[--replace --unattended --acceptTeeEula]

Where:

  • org_url: your Azure DevOps organization url
  • client_id: client ID of the service principal
  • tenant_id: tenant ID associated with the Entra ID
  • client_secret: client secret for the service principal
  • agent_name: name of the agent
  • agent_pool_name: name of the agent pool

For Example:

./config.sh --auth sp \
--url https://dev.azure.com/myorg/ \
--clientid f23d714e-259b-46fe-b5b3-7601f03b2090 \
--tenantid 0bf932af-ff5e-4c74-8772-334d3d1b8cf2 \
--clientsecret U2Fsd~GVkX195bnqi10aTpRNDVdappWv2WLwGw5W \
--agent agent01 --pool pool01 \
[--replace --unattended --acceptTeeEula]

Method 2 - Fetch AccessToken with Azure CLI

az login --service-principal --allow-no-subscriptions \
  --username <client_id> \
  --tenant <tenant_id> \
  --password <client_secret>
AZP_TOKEN=$(az account get-access-token \
--resource 499b84ac-1321-427f-aa17-267ca6975798 \
--query "accessToken" --output tsv)

./config.sh --auth pat \
--url <org_url> \
--token $AZP_TOKEN \
--agent <agent_name> --pool <agent_pool_name> \
[--replace --unattended --acceptTeeEula]
  • org_url: your Azure DevOps organization url
  • client_id: client ID of the service principal
  • tenant_id: tenant ID associated with the Entra ID
  • client_secret: client secret for the service principal
  • agent_name: name of the agent
  • agent_pool_name: name of the agent pool

For Example:

az login --service-principal --allow-no-subscriptions \
--username f23d714e-259b-46fe-b5b3-7601f03b2090 \
--tenant 0bf932af-ff5e-4c74-8772-334d3d1b8cf2 \
--password U2Fsd~GVkX195bnqi10aTpRNDVdappWv2WLwGw5W
AZP_TOKEN=$(az account get-access-token \
--resource 499b84ac-1321-427f-aa17-267ca6975798 \
--query "accessToken" --output tsv)

./config.sh --auth pat \
--url https://dev.azure.com/myorg/ \
--token $AZP_TOKEN \
--agent agent01 --pool pool01 \
[--replace --unattended --acceptTeeEula]

Method 3 - Fetch AccessToken with cURL

AZP_DATA="grant_type=client_credentials&client_id=<client_id>&client_secret=<client_secret>&resource=499b84ac-1321-427f-aa17-267ca6975798/.default"
AZP_TOKEN=$(curl -X POST -d $AZP_DATA https://login.microsoftonline.com/<tenant_id>/oauth2/token | jq -r '.access_token')

./config.sh --auth pat \
--url <org_url> \
--agent agent01 --pool pool01 \
--token $AZP_TOKEN \
[--replace --unattended --acceptTeeEula]
  • org_url: your Azure DevOps organization url
  • client_id: client ID of the service principal
  • tenant_id: tenant ID associated with the Entra ID
  • client_secret: client secret for the service principal
  • agent_name: name of the agent
  • agent_pool_name: name of the agent pool

For Example:

AZP_DATA="grant_type=client_credentials&client_id=f23d714e-259b-46fe-b5b3-7601f03b2090&client_secret=U2Fsd~GVkX195bnqi10aTpRNDVdappWv2WLwGw5W&resource=499b84ac-1321-427f-aa17-267ca6975798/.default"
AZP_TOKEN=$(curl -X POST -d $AZP_DATA https://login.microsoftonline.com/0bf932af-ff5e-4c74-8772-334d3d1b8cf2/oauth2/token | jq -r '.access_token')

./config.sh --auth pat \
--url https://dev.azure.com/myorg/ \
--agent agent01 --pool pool01 \
--token $AZP_TOKEN \
[--replace --unattended --acceptTeeEula]

Resources