Programmatically connecting to Azure Devops with a Service Principal (Subscription)


A previous post of mine Connecting to Azure Devops with a Service Principal has been popular since I have written it. Therefore, I’ve decided to extend on the topic and show how you can do it programatically with AZ DevOps.

You will need a few things already configured:

* See code in the powershell folder from the post on https://cann0nf0dder.wordpress.com/2020/09/14/app-only-auth-connect-to-sharepoint-online-with-msal-and-azure-keyvault/ to see how you can create this programatically.

Create a DevOps PAT token

  • Go to your Azure devops https://dev.azure.com
  • Sign in and click on User settings -> Personal access tokens
  • Click New Token
    • Give it a meaningful name so you know what the PAT token is for in the future. (E.g, Devops Service Connection)
    • Select your Organization
    • Select the Expiration date for as long as you need. Maximum 1 Year
    • Select Scopes at Full access (You might want to tighten your permission in a production environment, for this demo Full access is fine).
    • Click Create
  • Once you have clicked Create this is the only chance to grab a copy of the token. Please take a copy of this token as you will require it later.

The Code

You will need to first be logged into Az Cli. You can sign in using a service principal as you might with a pipeline, as long as the account being used is able to list App Registrations, and ‘User Access Administrator’ RBAC role to be able to apply contribute access to the DevOps service principal on the subscription (Line 43) .

The important part to note in the code is how the authentication works with Devops. The Personal Access Token is added to the $Env: variable “AZURE_DEVOPS_EXT_PAT”. (Line 32)

<#
.SYNOPSIS
Creates a service connection for a subscription
Please ensure you are already logged to azure using az login
#>
param(
# Azure DevOps Personal Access Token (PAT) for the 'https://dev.azure.com/%5BORG%5D&#39; Azure DevOps tenancy
[Parameter(Mandatory)]
[string]
$PersonalAccessToken,
# The Azure DevOps organisation to create the service connection in, available from System.TeamFoundationCollectionUri if running from pipeline.
[string]
$TeamFoundationCollectionUri = $($Env:System_TeamFoundationCollectionUri -replace '%20', ' '),
# The name of the project to which this build or release belongs, available from $(System.TeamProject) if running from pipeline
[string]
$TeamProject = $Env:System_TeamProject,
[string]
$AppRegistrationName,
[securestring]
$AppPassword
)
$ErrorActionPreference = 'Stop'
$InformationPreference = 'Continue'
$account = az account show | ConvertFrom-Json
#Clearing default.
az configure –defaults group=
$Env:AZURE_DEVOPS_EXT_PAT = $PersonalAccessToken
Write-Information -MessageData:"Adding Azure DevOps Extension…"
az extension add –name azure-devops
Write-Information -MessageData "Configure defaults Organization:$TeamFoundationCollectionUri …"
az devops configure –defaults organization="$TeamFoundationCollectionUri"
Write-Information -MessageData "Getting App Registration: $AppRegistrationName…"
$AppReg = az ad app list –all –query "[?displayName == '$AppRegistrationName']" | ConvertFrom-Json
Write-Information -MessageData "Give App Registration Contributor access to Subscription…"
az role assignment create –role 'Contributor' –assignee $($AppReg.appId)
Write-Information -MessageData "Checking if $TeamProject project exists…"
$ProjectDetails = az devops project list –query "value[?name == '$TeamProject']" | ConvertFrom-Json
if(-not $ProjectDetails){
Write-Information -MessageData "Creating $TeamProject project…"
$ProjectDetails = az devops project create –name $TeamProject
}
Write-Information -MessageData "Checking if service endpoint already exists…"
$ServiceEndpoint = az devops service-endpoint list –project "$TeamProject" –query "[?name == '$($AppReg.DisplayName)-Subscription']" | Select-Object -First 1 | ConvertFrom-Json
if(-not $ServiceEndpoint){
Write-Information -MessageData "Creating Service Connection name:$($AppReg.DisplayName)-Subscription for project $TeamProject…"
$Env:AZURE_DEVOPS_EXT_AZURE_RM_SERVICE_PRINCIPAL_KEY = $(ConvertFrom-SecureString -SecureString:$AppPassword -AsPlainText)
$ServiceEndpoint = az devops service-endpoint azurerm create –project "$TeamProject" –name "$($AppReg.DisplayName)-Subscription" –azure-rm-service-principal-id "$($AppReg.appId)" –azure-rm-subscription-id "$($Account.id)" –azure-rm-subscription-name "$($Account.name)" –azure-rm-tenant-id "$($Account.tenantId)" | ConvertFrom-Json
}
Write-Information -MessageData "Updating Service Connection to be enabled for all pipelines…"
az devops service-endpoint update –project "$TeamProject" –id "$($ServiceEndpoint.id)" –enable-for-all true | Out-Null

To run the above code, you will need to put in your parameters. Replace with your values then run the script, this will call the script above.

$PersonalAccessToken = '<Put your PAT Token>'
$TeamProject = '<Project Name>'
$TeamFoundationCollectionUri = 'https://dev.azure.com/<OrganizationName >'
$AppRegistrationName = '<Service Principal Name>'
$AppPassword = '<Service Principal Secret>'
$AppSecurePassword = ConvertTo-SecureString -String:$AppPassword -AsPlainText -Force
.\Install-ServiceConnectionSubscription.ps1 -PersonalAccessToken $PersonalAccessToken `
-TeamFoundationCollectionUri:$TeamFoundationCollectionUri `
-TeamProject:$TeamProject `
-AppRegistrationName:$AppRegistrationName `
-AppPassword:$AppSecurePassword

My team project is called AutomateDevOps, and I used an App Registration called DevOps.

Running Script

Service Principal with Contribute on Subscription

Project ‘AutomateDevOps’ and Service connection ‘DevOps-Subscription’

My next blog post explains how do make a Management Group Service Connection instead of a Subscription level. ‘Programmatically connecting to Azure Devops with a Service Principal (Management Group)

One thought on “Programmatically connecting to Azure Devops with a Service Principal (Subscription)

  1. Pingback: Programmatically connecting to Azure DevOps with a Service Principal (Management Group) | SharePoint and other geeky stuff

Comments are closed.