Automating Azure DevOps Service Connections

Windows PowerShell, Azure Infrastructure, Azure DevOps, DevOps
Azure Pipelines Icon

Overview

Recently I was working on doing infrastructure deployments using Azure DevOps Pipelines. One of the first things that needs to be done is to create a Service Connection to the target environment. In my case, my target environment is an Azure Subscription and I’ll use a Service Principal with an ID and Key (versus a Certificate) for authentication. However, we want to avoid storing this authentication information and we want it automated.

I also don’t want my Service Principal to have broad privileges so it’s scope will be limited to a single Resource Group. Let’s create several Resource Groups, a Service Principal for each one, assign it privileges and create a corresponding Service Connection in Azure Dev Ops

 

Oh, so many parameters

First, let’s define some parameters and set some variables. Most of these are self-explanatory:

#region 
#region Parameters
$cloud = "AzureCloud"
$location = 'eastus'
$tagDept = "specialprojects"
$tagEnv = "dev"
$devOpsUrl = 'https://dev.azure.com/M365x'
$devOpsProject = 'infra'
$resourceUrl = https://management.core.windows.net/$apps = @{
     'logging'="2";
     'devops'="2";
     'domain'="1";
     }
#endregion
PowerShell

The $apps parameter is a hashtable that will be used in the name of the Resource Group name and Service Principal. The number next to each one is part of my Resource Tags.

Next, we’re going to login while saving the context so we can gather more variables:

PowerShell

We also need the Access Token that we’ll use later to make a REST API call to Azure DevOps:

PowerShell

 

Loop it

We’re almost ready to get to work. Since we have 3 Resource Groups defined in $apps (and could easily expand this to several dozen), we need a foreach loop. We’ll also set some additional variables:

PowerShell

These variables are just setting the names of the Resource Groups and Service Principal. If you have a different standard, modify these. Also, this is where we set the scope to the Resource Group. If you prefer to have a Subscription-wide scope, just remove /resourceGroups/$rgName.

Next, we’ll create the Resource Group and Service Principal using these values:

PowerShell

Let me explain the last two parameters:

  • $spNameId – This is the Service Principal ID and will look like a GUID
  • $spkey – This is the password for the Service Principal. We need to use this later to create the Service Connection later but after that, we don’t really need to know it. It’s available in memory for a short time, until the next item in the loop or once the session is closed but we don’t have to store it anywhere (thus improving security).

The last thing we need to do is to create the Service Connection in Azure DevOps. I’m not aware of an official PowerShell module but there is an Azure CLI extension. The problem with the Azure CLI is that it has limited support for creating Service Endpoints (Service Connections) and is in preview. Therefore, we’ll call the REST API directly, using PowerShell:

PowerShell

Because that was in a foreach loop, we can easily create many Resource Groups, a Service Principal for each one, assign it Contributor rights on the Resource Group, and create a Service Connection.

 

Conclusion

Now, we can create Pipelines that use these Service Connections to connect to Azure Resource Manager. No passwords or secrets are kept insecurely and our Service Principals are using limited rights.

I mentioned that there was not an official PowerShell module for Azure DevOps. However, here are some community projects; I have not tried any of these:

For more information on using Pipelines for infrastructure, check out these great posts from Barbara 4bes:

Is there a better way to do this, got any ideas? Post a comment below.

1 comment… add one

Leave a Reply