
Introduction
This blog post is part of this years Azure Spring Clean an event which is ran to promote well managed Azure tenants. To achieve this, they have community driven articles that highlight best-practice, lessons learned, and help with some of the more difficult topics of Azure Management.

Azure Policy is a powerful governance tool that helps organizations enforce compliance across their Azure environments. By automating the deployment of Azure Policies using Bicep and the Azure Verified Modules (AVM) GitHub repository, you can ensure consistent policy enforcement while leveraging modular, reusable infrastructure as code.
This guide assumes you already have your environment set up in VS Code, including Bicep tooling and Azure CLI authentication.
Prerequisites
Before deploying Azure Policies with Bicep, ensure you have:
- VS Code with the Bicep extension installed.
- Azure CLI installed and authenticated (
az login
). - Bicep CLI installed (
az bicep install
if needed). - Git installed and cloned the Azure Verified Modules (AVM) repository.
- Appropriate permissions to create and assign policies in Azure.
Deploying Policies to Management Groups and Subscriptions
Deploying policies at the management group level is a best practice for organizations that manage multiple subscriptions under a common governance framework. By applying policies at this higher level, you can ensure:
- Consistency: Enforce compliance standards across all subscriptions within the management group without the need for redundant deployments.
- Efficiency: Reduce operational overhead by managing policies centrally instead of applying them individually to each subscription.
- Scalability: As new subscriptions are added to the management group, they automatically inherit the assigned policies, ensuring continuous compliance.
To apply policies at different scopes, use the following commands:
Deploying to a Management Group
$location = ‘West Europe’
$management-group-id = ‘mg-demo’
az deployment mg create \
--management-group-id $management-group-id \
--location $location \
--template-file main.bicep \
--parameters @parameters.json \
--name MGPolicyDeployment
Deploying to a Subscription
az deployment sub create \
--location eastus \
--template-file main.bicep \
--parameters @parameters.json \
--name SUBPolicyDeployment
You can also check in the Azure Portal under Policy -> Assignments
Lets take a look at some example Azure Policies you may want to add to your management groups. In this example I would add them to a file called deployPolicyMg.bicep
targetScope="managementGroup"
@description('Policy Assignment Management Group - Allowed Locations')
module assignAllowedLocationPolicy 'policyAssignmentMg.bicep' = if (deployAllowedLocations) {
name: 'AllowedLocations'
params: {
name: 'Allowed Locations'
displayName: 'Allowed Locations'
policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c'
location: primaryLocation
identity: 'None'
parameters:{
listOfAllowedLocations: {
value: allowedLocations
}
}
}
}
@description('Policy Assignment Management Group - ISO 27001-2013')
module assignIso27001Policy 'policyAssignmentMg.bicep' = if (deployIso27001Policy) {
name: 'Iso27001'
params: {
name: 'ISO 27001-2013'
displayName: 'ISO 27001-2013'
policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/89c6cddc-1c73-4ac1-b19c-54d1a15a42f2'
location: primaryLocation
identity: 'SystemAssigned'
roleDefinitionIds: []
}
}
@description('Policy Assignment Management Group - Azure Security Benchmark')
module assignAscPolicy 'policyAssignmentMg.bicep' = if (deployAzureSecurityBenchmark) {
name: 'AzureSecurityBenchmark'
params: {
name: 'Azure Security Benchmark'
displayName: 'Azure Security Benchmark'
policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8'
location: primaryLocation
identity: 'None'
roleDefinitionIds: []
}
}
The above code example makes use of some variables which I add to a .bicepparameters file which would look like this:-
using './deployPolicyMg.bicep'param deployAllowedLocations = true
param deployIso27001Policy = true
param deployAzureSecurityBenchmark = true
Lets take a look at some example Azure Policies you may want to add to a subscription. In this example I would add them to a file called deployPolicySub.bicep
targetScope="subscription"
@description('Assign Policies to Subscription - Require an Owner tag on resource groups')
module assignReguireRgOwnerTagPolicy 'policyAssignmentSub.bicep' = if (tagAtSubscriptionLevel && ownerTagResourceGroupsPolicy) {
name: 'reguireRgOwnerTagPolicy'
params: {
name: 'Require an Owner tag on resource groups'
displayName: 'Require an Owner tag on resource groups'
policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/96670d01-0a4d-4649-9c89-2d3abc0a5025'
location: primaryLocation
identity: 'None'
parameters:{
tagName: {
value: ownerTagName
}
}
}
}
@description('Assign Policies to Subscription - Require a DeployedBy tag on resource groups')
module assignReguireRgDeployedByTagPolicy 'policyAssignmentSub.bicep' = if (tagAtSubscriptionLevel && deployedByTagResourceGroupsPolicy) {
name: 'reguireRgDeployedByTagPolicy'
params: {
name: 'Require a DeployedBy tag on resource groups'
displayName: 'Require a DeployedBy tag on resource groups'
policyDefinitionId: '/providers/Microsoft.Authorization/policyDefinitions/96670d01-0a4d-4649-9c89-2d3abc0a5025'
location: primaryLocation
identity: 'None'
parameters:{
tagName: {
value: deployByTagName
}
}
}
}
The code above is an example of how you could add Azure Policies into a subscription.
The above code example makes use of some variables which I add to a .bicepparameters file which would look like this:-
using './deployPolicySub.bicep'
param tagAtSubscriptionLevel = true
param ownerTagResourceGroupsPolicy = true
param deployedByTagResourceGroupsPolicy = true
Conclusion
By leveraging Azure Bicep and Azure Verified Modules, you can automate and standardize Azure Policy deployment efficiently. Start using AVM today to maintain governance and compliance effortlessly!