How to deploy Azure Policy from an Azure DevOps pipeline

Search for a command to run...

No comments yet. Be the first to comment.
If you have been following my experiments for hosting and running Ghost on Azure, you might recall that I tried hosted it on Azure Web App for Containers first, using the Docker Compose for running a

I recently presented on a webinar hosted by the Turbo360 team and Michael Stephenson, the host of Azure on Air and FinOps on Azure podcasts. There, we discussed the most common mistakes in optimizing compute costs in Azure and how to avoid them, the ...

I’ve been watching the development of Radius, a new application hosting platform that originated in the Microsoft Azure Incubations team and later became a CNCF project, for a while, and I finally managed to dedicate some time to trying it in practic...

It has been some time since I wrote my Azure Policy Starter Guide, in which I briefly touched upon the challenges of testing custom Azure Policy definitions. Azure Policy testing still remains an open question for me, offering a lot of room for vario...

When optimizing cloud costs for large enterprise environments, it’s common to focus on compute-intensive cloud resources, such as virtual machines, clusters, and container-based workloads, as they are usually the primary cost driver and top contribut...

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.
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.
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!