After publishing my posts about deploying Azure Policy and Azure Policy initiatives from ARM templates, I got a few questions about performing such deployments from Azure DevOps pipelines. Indeed, there are a few things to pay attention to. So, I will try to shed some light on them in this article.
Azure pipeline tasks
If you define your policies in ARM templates as I do, you can include a step with the Azure Resource Manager (ARM) Template Deployment Task, which is the successor of the older Azure Resource Group Deployment Task, in your pipeline. This new version has many more deployment options, especially targeting your deployments to a resource group, subscription or management group. It also supports Validate mode for your deployment, so you can check first whether your template is syntactically correct. Additionally, if you target your deployments to multiple environments requiring different configurations, you can override template parameters and keep your repository clean from multiple parameter files.
The Azure DevOps product team recently updated the pipeline UI to support that new ARM template deployment task, but I suggest always checking the Azure Pipelines Tasks repository on GitHub first for recent changes and updates.
If you have some build scripts in your project to compile and deploy Azure Policy artifacts from them in batch, then you can use the well-known ‘New-AzDeployment’ and ‘Test-AzDeployment’ PowerShell cmdlets for subscription-level deployments, which is usually the case for Azure Policies. Azure PowerShell tasks are at your service to run the scripts.
Pay attention to the fact that both cmdlets support input of ARM template parameters from a ‘TemplateParameterObject’, which is a simple hashtable. That option allows you to implement a similar override pattern for template parameters and perform conditional deployments.
For example, the following code reads a template parameter file for policy assignment, extracts the parameters into a hashtable and changes or adds additional deployment parameters based on input script parameters or its variables:
Apart from that, you can create a master (or main) template for deploying your custom policy and initiative definitions and their assignment from linked templates. If you are working in a private repository, you might consider creating a pipeline that copies your linked templates to a storage account during deployment.
As you can see, there are plenty of options for deploying Azure Policy from a pipeline, but the final choice depends on your objectives, limitations and used build/test/deploy patterns.
Configuring permissions to deploy Azure Policy
When you try to run your pipeline that has deployment tasks for Azure Policy artifacts for the first time, you most likely will get the following error:
Authorization failed for template resource '<your_policy_name>’ of type 'Microsoft.Authorization/policyDefinitions'. The client '’ with object id '' does not have permission to perform action 'Microsoft.Authorization/policyDefinitions/write' at scope '/subscriptions/046a3b8b-ca72-46b7-8bd6-4a7cc5357741/providers/Microsoft.Authorization/policyDefinitions/<your_policy_name>’
That error message indicates some permission issues, as some processes cannot perform the ‘write’ operation in the ‘Microsoft.Authorization/policyDefinitions’ namespace. So, let’s sort it out piece by piece.
Firstly, the authorization has failed for a specific resource in your ARM template, and that resource type is Azure Policy. Secondly, the authorization did not succeed for a client with a particular ID, which is represented as GUID, when it tried to create a new resource in the target namespace and target scope. At the same time, if you try deploying the same ARM template manually, the deployment completes successfully provided that you are an administrator on the subscription and the template is valid.
As the deployment tasks run in the pipeline context, you might assume that there is something wrong with the permissions for the service connection to your Azure subscription, which is used in your pipeline. So, let’s check what configuration we have for that service connection in your Azure DevOps project:
To get the extended information on the screen above, click on ‘use the full version of the service connection dialog’ at the bottom of the default connection properties windows.
Here, you might notice that the service principal client ID and the GUID from the error message are the same, so our assumption about the pipeline context was right.
Next, let’s check Access control for your subscription on the Azure portal. You will see that there are a few role assignments that are named similar to your Azure DevOps projects:
When looking into the assignment properties related to your project, you also might notice the same ID:
By default, Azure DevOps grants ‘Contributor’ permissions for the service principals used to authenticate pipelines to Azure, which are fine for most regular deployments. However, this built-in role doesn’t have permission to deal with Azure Policy resources.
Granting our service principal extensive administrative permissions in the subscription is not considered a good security practice, so there should probably be another option. Indeed, the built-in ‘Resource Policy Contributor’ role exists, which has the permissions we need to work with Azure Policy.
You can use the following PowerShell command to assign that additional role to your service principal and re-run the pipeline:
New-AzRoleAssignment -ObjectId (Get-AzADServicePrincipal -ApplicationId <your_service_principal_client_ID>).Id -RoleDefinitionName 'Resource Policy Contributor'
Now, you shouldn’t see the permission error anymore.
I hope this information will help you to create an Azure DevOps pipeline for Azure Policy and deploy policies and policy initiatives as part of your deployment process.
If you have any questions or suggestions, go ahead and post them in the comments!