Creating quick service connections to Azure from Azure DevOps can be easy. Creating secured, easy-to-manage, connections is harder.
The Easy Connections
If you’re a Project Administrator or Endpoint Administrator on a Team project, you can create a new Service Connection. For Azure Service Connections, you also need Owner rights to the respective subscription and the ability on Azure Active Directory to create new app registrations.
From a Team Project, you can go to Settings and Service Connections. From there, you can create a new service connection.
For more information, here’s the Microsoft docs.
Guidelines
Following the principle of least priviledge, the smaller the scope for a service principal the better. In other words, if you can scope it down to a resource group even better.
The Problem
Today, when creating multiple Azure DevOps service principals with limited access, they will all show up with unfriendly names in Azure Active Directory. For a Team Project with many Azure service connections, you might end up with several service principals with the same name - making it very difficult to segregate access for each one.
For example
I created two service connections with Azure DevOps. I scoped these to a facundo-rg
resource group.
From the IAM blade in facundo-rg
, there’s the service principals created for this team project.
Although there’s two service connections, they have the same names! The name is just a combination of the Team Project and the Subscription ID.
It’s impossible to see which service principal belongs to which Azure DevOps service connections.
The Solution - Do it yourself
Note: Inspiration taken from the Azure DevOps labs
Bash
subscriptionId=[Some subscription Id]
resourceGroupName1=facundo-rg
resourceGroupName2=facundo2-rg
az ad sp create-for-rbac -n "test-my-app3" --role contributor \
--scopes /subscriptions/$subscriptionId/resourceGroups/$resourceGroupName1 \
/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName2
Result will look like
{
"appId": "[some app id]",
"displayName": "test-my-app3",
"name": "http://test-my-app3",
"password": "[some password]",
"tenant": "[some tenant]"
}
Then from Azure DevOps, use the link to manually complete the service connection.
- Service Principal Client ID -
appId
- Service Principal Key -
password
- Tenant -
tenant
- Subscription ID - your subscription id
- Subscription Name - the name of your subscription
Extra Credit
Use the Azure DevOps extension for the Azure CLI to also automate the creation of the service connection. See more here.
Note: Install the Azure DevOps CLI extension first.
teamProject="Service Principals Demo"
subscriptionId=$(az account show | jq -r '.id')
subscriptionName=$(az account show | jq -r '.name')
resourceGroupName1=facundo-rg
resourceGroupName2=facundo2-rg
name="test-my-app3"
response=$(az ad sp create-for-rbac -n $name --role contributor \
--scopes /subscriptions/$subscriptionId/resourceGroups/$resourceGroupName1 \
/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName2)
appId=$(echo $response | jq -r '.appId')
tenantId=$(echo $response | jq -r '.tenant')
export AZURE_DEVOPS_EXT_AZURE_RM_SERVICE_PRINCIPAL_KEY=$(echo $response | jq -r '.password')
az devops service-endpoint azurerm create --azure-rm-service-principal-id "$appId" \
--azure-rm-subscription-id "$subscriptionId" \
--azure-rm-subscription-name "$subscriptionName" \
--azure-rm-tenant-id "$tenantId" \
--name "$name" \
--project "$teamProject"