Building your Azure Policies (Azure DevOps) – Part 2

As written in Part 1, policies are used to maintain the state. The Azure portal itself contains a lot of OOTB policies, but you also want to create and deploy your own. This part will go over how to deploy custom policy definitions using Azure DevOps.

Script

The script shared in part 1 is adjusted to read out the policy definition files within a directory. This is done because you do not want to deploy just one definition per pipeline. Below the updated PowerShell script is added.

[CmdletBinding()]
Param(
    [Parameter(Mandatory = $true)]
    [ValidateSet('Subscription', 'Managementgroup')]
    [string]$Scope,
    [Parameter(Mandatory = $true)]
    [string]$ScopeName,
    [Parameter(Mandatory = $true)]
    [string]$PolicyFolder,
    [Parameter(Mandatory = $false)]
    [string]$RoleIds
)
 
$policyFiles = Get-ChildItem -Path $PolicyFolder -Recurse -Filter "*.json"
foreach ($policyFile in $policyFiles) {
 
    Write-Output "Working on Policy: $($policyFile.Name)"
 
    $policyDefinitionFileContent = Get-Content -Raw -Path $PolicyFile
    $policyDefinitionFile = ConvertFrom-Json $policyDefinitionFileContent
    $policyDefinitionName = $policyDefinitionFile.properties.displayName
 
    $parameters = @{}
    $parameters.Add("Name", $policyDefinitionName)
    switch ($Scope) {
        "ManagementGroup" {
            $parameters.Add("ManagementGroupName", $ScopeName)
        }
        "Subscription" {
            $sub = Get-AzSubscription -SubscriptionName $ScopeName
            $parameters.Add("SubscriptionId", $sub.Id)
        }
    }
 
    $definition = Get-AzPolicyDefinition @parameters -ErrorAction SilentlyContinue
 
    $parameters.Add("Policy", $policyDefinitionFileContent)
    if ($definition) {
        Write-Output "Policy definition already exists, policy will be updated"
    }
    else {
        Write-Output "Policy does not exist"
    }
 
    New-AzPolicyDefinition @parameters
}

Policy definitions can be saved in Azure DevOps as code. The definitions in source control can be deployed via Azure DevOps Pipelines.

Prerequisites

To be able to start deploying the definitions, we need to have the following in place:

  • Service principal in Azure Active Directory
  • Service Connection in Azure DevOps
  • Access rights in Azure
  • Pipeline

First couple of prerequisites

We will need a service principal to deploy policy definitions via Azure DevOps. Creating this can be done via the portal. When the principal is made, give that principal the correct permissions on the scope where you want to deploy the definitions. I will provide the principal access to the management group where the policies need to be deployed for this article.

Of course, we can give the principal owner permissions on the scope, but we want to stick to the least privileges. Therefore we provide the principal the ‘Resource Policy Contributor’ role, which is enough for deploying Azure Policies.

With the rights in place, the service connection in Azure DevOps can be configured. In Azure DevOps, create an “Azure Resource Manager” service connection and fill in the correct information regarding your platform.

Pipeline

Next up is the pipeline. For the pipeline, we will start with an empty one that we save in a GitHub repository, where we also save the policy definition files. From the empty pipeline, remove the default tasks and add an Azure PowerShell task that connects to the Service Connection we created.

Point this task to the correct script file in the repository and ensure the arguments are supplied using variables. The Yaml of the task will look like the snippet below.

- task: AzurePowerShell@5
  inputs:
    azureSubscription: 'Root Management Group Connection'
    ScriptType: 'FilePath'
    ScriptPath: './scripts/azpolicy.ps1'
    ScriptArguments: '-Scope "$(scope)" -ScopeName "$(scopeName)" -PolicyFolder "$(folder)"'
    azurePowerShellVersion: 'LatestVersion'
    pwsh: true

Bringing this all together will result in a simple pipeline like below.

trigger:
- main
 
pool:
  vmImage: ubuntu-latest
 
variables:
  - name: scope
    value: "ManagementGroup"
  - name: scopeName
    value: "mgName"
  - name: folder
    value: "./policies/deploy"
 
steps:
- task: AzurePowerShell@5
  inputs:
    displayName: 'Deploy Azure Policy Definitions'
    azureSubscription: 'Root Management Group Connection'
    ScriptType: 'FilePath'
    ScriptPath: './scripts/azpolicy.ps1'
    ScriptArguments: '-Scope "$(scope)" -ScopeName "$(scopeName)" -PolicyFolder "$(folder)"'
    azurePowerShellVersion: 'LatestVersion'
    pwsh: true

Of course, this is not a production-grade solution, but it highlights how to manage your policy definitions in code and how to deploy them. In the following article, we will deploy definitions via GitHub Actions.

This blog featured as part of Azure Week. Find more great Azure content here.

About the Author:

Maik van der Gaag is the CTO of 3fifty, an experienced consultancy company with a strong focus on the Microsoft Cloud. He has over 15 years of experience providing architecture, development, training, and design expertise. During his work, he works on a variety of projects ranging from Cloud Transformations to DevOps implementations.

He loves to share his knowledge which was also one of the reasons why he founded the Dutch Cloud Meetup. Maik is a public speaker, who writes blogs, and organizes events. Microsoft has recognized him as Microsoft Azure MVP.

Reference:

van der Gaag, M. (2022). Building your Azure Policies (Azure DevOps) – Part 2. Available at: https://msftplayground.com/2022/03/building-your-azure-policies-azure-devops-part-2/ [Accessed: 30th June 2022].

Share this on...

Rate this Post:

Share:

Topics:

Azure

Tags: