Azure Service Connections in Azure DevOps
When you create a Service Connection in Azure DevOps, you’re trusting the system with a credential and connection config to an external system. In the case of Azure, most Service Connections i’ve seen enterprises use are created at the Subscription scope, after a subscription has been created.
This is great when the subscription has been created, but what about the case when it hasn’t? What about if it’s actually your pipeline that’s initiating a request for a subscription to another system, or if you want your pipeline to be totally agnostic of subscriptions and operate dynamically from pipeline inputs.
Niche? Perhaps, but lets look at how we’d can accomplish it.
Create the Service Principal
It’s important to understand that when you create a Service Connection in Azure, it automates the creation of a Service Principal. The exception here is Managed Identities, which are out of scope for this post.
There are many ways to create a Service Principal in Azure, I tend to like using the AZ CLI.
az ad sp create-for-rbac -n "MyAppSp"
Create the Service Connection
After you’ve created a Service Principal (not requiring RBAC access to any subscriptions) we can then;
- Create a New Azure service connection with Service Principal (manual) as the authentication method.
- Specify a Management Group scope, but not not provide any Management Group details.
- Provide the Service Principal AppId and Secret in the respective fields.
- Finally as good practice, untick the Grant access permission to all pipelines option.
Once the Service Connection name is known, we can consume it in our pipeline.
When the pipeline task runs, it’s important to note that a Management Group Scoped Service Connection logs into Azure with the –allow-no-subscriptions option set, so that we’re not explicitly logging into a subscription. Therefore when you have a task where you do want to deploy resources to a subscription you should ensure the az account set -s SUBSCRIPTIONID command is run first.
In my pipeline example, i’m searching for the existence of a subscription and then persisting its SubscriptionId in a variable group to be used by other tasks.