Skip to main content
Jorge Bernhardt Jorge Bernhardt
  1. Posts/

Bicep - Creating Custom Azure Policy Initiatives

·1048 words·5 mins· 100 views · 5 likes ·
Azure CLI Azure Cloud Shell Microsoft Microsoft Azure

Hi everyone! This week we’re talking again about “Policy as Code,” an approach that brings consistency and efficiency to policy management, similar to how “Infrastructure as Code” transformed infrastructure deployment.

This time, I will use Bicep, Microsoft’s language ideal for defining and deploying Azure resources, including Azure policies.

Azure Policy allows us to establish and apply rules that ensure our resources meet operational and security standards. In this post, we will focus on implementing groups of related policies, known as “Initiatives”, that help ensure that our solutions comply with various regulations.

In this example, we will create an initiative with 10 policies to help control storage accounts. This is just one example of the many possibilities that Policy as Code offers with Bicep.

This guide will explain how to implement your own Azure Policy initiatives using Bicep. For more information on how to assign these initiatives once they are created, check out this post.

Prerequisites>

Prerequisites #

Before you start, you’ll need the following to deploy and manage resources with Bicep:

  • You need Azure CLI version 2.20.0 or later to deploy Bicep files on your local machine.
  • A text editor or IDE of your choice (Visual Studio Code with Bicep extension is my recommendation)
Create the Bicep files>

Create the Bicep files #

The first step in implementing the Bicep template is to create the Bicep file that describes the resources we plan to manage. Create a new file called PolicyInitiative.bicep. This file will contain the code necessary to define and configure the implementation of your policy initiatives.

// Set the target scope to 'subscription' level.
targetScope = 'subscription'

@description('Name of the initiative.')
param initiativeName string

@description('Description of the initiative.')
param initiativeDescription string

@description('Category of the initiative.')
param initiativeCategory string

@description('Version of the initiative.')
param initiativeVersion string

@description('List of policies in the initiative.')
param policies array

// Define a resource for a policy set (initiative) in Azure Policy.
resource storageGovernanceInitiative 'Microsoft.Authorization/policySetDefinitions@2023-04-01' = {
  name: initiativeName
  properties: {
    policyType: 'Custom' 
    displayName: initiativeName 
    description: initiativeDescription 
    metadata: {
      category: initiativeCategory
      version: initiativeVersion 
    }
    // Define the policy definitions included in this initiative.
    policyDefinitions: [
      for policy in policies: { // Iterate over each policy in the 'policies' parameter.
        policyDefinitionId: policy.policyId
        parameters: policy.parameters
      }
    ]
  }
}

// Output the resource ID of the created policy set.
output initiativeId string = storageGovernanceInitiative.id
Deployment scope>

Deployment scope #

In Bicep, you can deploy your project to different levels such as resource groups, subscriptions, management groups, or even the entire tenant. However, the appropriate scopes for deploying policy initiatives like the one in the script are usually subscriptions or management groups. For this script, I’ve chosen a subscription as our deployment scope. This is ideal for policies that affect many resources or entire services within a subscription, helping to apply rules widely and ensure compliance effectively.

Deploy the Bicep template using the Azure CLI>

Deploy the Bicep template using the Azure CLI #

Once your Bicep template is prepared, and you’ve selected your desired scope, you can proceed to deploy the template through the Azure CLI. To do so, execute the following commands.

Parameters>

Parameters #

The parameters file is a crucial component when deploying your Bicep template as it contains all the configurations and configurable values that the template will use. In this case, for an Azure Policy initiative, the parameters file includes definitions for each policy that is part of the initiative; Here is an example.

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
      "initiativeName": {
        "value": "azure-storage-governance"
      },
      "initiativeDescription": {
        "value": "Governance rules for Azure Storage ensuring compliance and security."
      },
      "initiativeCategory": {
        "value": "Storage Security"
      },
      "initiativeVersion": {
        "value": "1.0.0"
      },
      "policies": {
        "value": [
          {
            "policyId": "/providers/Microsoft.Authorization/policyDefinitions/fe83a0eb-a853-422d-aac2-1bffd182c5d0",
            "parameters": {
              "effect": {
                "value": "Audit"
              },
              "minimumTlsVersion": {
                "value": "TLS1_2"
              }
            }
          },
          {
            "policyId": "/providers/Microsoft.Authorization/policyDefinitions/b2982f36-99f2-4db5-8eff-283140c09693",
            "parameters": {
              "effect": {
                "value": "Deny"
              }
            }
          },
          {
            "policyId": "/providers/Microsoft.Authorization/policyDefinitions/f81e3117-0093-4b17-8a60-82363134f0eb",
            "parameters": {
              "effect": {
                "value": "Modify"
              }
            }
          },
          {
            "policyId": "/providers/Microsoft.Authorization/policyDefinitions/c9d007d0-c057-4772-b18c-01e546713bcd",
            "parameters": {
              "effect": {
                "value": "Audit"
              }
            }
          },
          {
            "policyId": "/providers/Microsoft.Authorization/policyDefinitions/8c6a50c6-9ffd-4ae7-986f-5fa6111f9a54",
            "parameters": {
              "effect": {
                "value": "Audit"
              }
            }
          },
          {
            "policyId": "/providers/Microsoft.Authorization/policyDefinitions/bc1b984e-ddae-40cc-801a-050a030e4fbe",
            "parameters": {
              "effect": {
                "value": "Audit"
              }
            }
          },
          {
            "policyId": "/providers/Microsoft.Authorization/policyDefinitions/c36a325b-ae04-4863-ad4f-19c6678f8e08",
            "parameters": {
              "effect": {
                "value": "Audit"
              }
            }
          },
          {
            "policyId": "/providers/Microsoft.Authorization/policyDefinitions/bfecdea6-31c4-4045-ad42-71b9dc87247d",
            "parameters": {
              "effect": {
                "value": "Audit"
              }
            }
          },
          {
            "policyId": "/providers/Microsoft.Authorization/policyDefinitions/92a89a79-6c52-4a7e-a03f-61306fc49312",
            "parameters": {
              "effect": {
                "value": "Audit"
              }
            }
          },
          {
            "policyId": "/providers/Microsoft.Authorization/policyDefinitions/7433c107-6db4-4ad1-b57a-a76dce0154a1",
            "parameters": {
              "effect": {
                "value": "Deny"
              },
              "listOfAllowedSKUs": {
                "value": [
                  "Standard_LRS",
                  "Premium_LRS"
                ]
              }
            }
          }
        ]
      }
    }
  }
Parameter file explanation>

Parameter file explanation #

Initiative Details:

  • initiativeName: This parameter specifies the name of the policy initiative.
  • initiativeDescription: This parameter provides a description of what the initiative aims to achieve.
  • initiativeCategory: This parameter categorizes the initiative, helping to organize and manage it within Azure Policy.
  • initiativeVersion: This parameter tracks the version of the initiative, useful for updates and version control.

Policies:

  • policyId: Each policy included in the initiative is identified by its unique policy definition ID, which can be found in the Azure Policy service under policy definitions.
  • parameters: Each policy can have specific parameters that configure its behavior. These parameters can include settings like the effect of the policy (e.g., Audit, Deny) and other customizable settings that the policy might require.
Preview changes>

Preview changes #

Before deploying a Bicep file, you can preview the changes that will occur to your resources. Using what-if operations does not change existing resources; it simply shows you an output that includes color-coded results that allow you to see different changes.

az deployment sub what-if \
--template-file <filename>.bicep \
--parameters @<filename>.parameters.json \
--location <location>
Deploy the Azure resource>

Deploy the Azure resource #

Finally, to deploy the template, run the following command.

az deployment sub create \
--template-file <filename>.bicep \
--parameters @<filename>.parameters.json \
--location <location>
Validate the deployment>

Validate the deployment #

To verify that the resource was created correctly, you can either use the Azure Portal or the Azure CLI to check the created resources and their configurations. For Azure CLI, use the following command.

az policy set-definition list \
--query "[?policyType=='Custom']" \
--output table

References and useful links #

Thank you for taking the time to read my post. I sincerely hope that you find it helpful.