Azure Policy is a powerful tool for enforcing organizational standards and compliance.
Let’s see it in action. Imagine you want to ensure all virtual machines deployed in your Azure environment use only approved VM sizes. This prevents users from deploying expensive or unapproved VM types.
Here’s how you’d set that up. First, you define a custom policy.
{
"mode": "All",
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Compute/virtualMachines"
},
{
"not": {
"field": "Microsoft.Compute/virtualMachines/sku.name",
"in": [
"Standard_D2s_v3",
"Standard_D4s_v3",
"Standard_D8s_v3",
"Standard_DS2_v2",
"Standard_DS3_v2"
]
}
}
]
},
"then": {
"effect": "Deny"
}
},
"parameters": {}
}
This policy definition has two main parts: the if condition and the then action. The if block specifies what to look for. Here, we’re checking if the resource type is Microsoft.Compute/virtualMachines and if its sku.name (the VM size) is not in our approved list. The then block dictates what happens if the if condition is met. In this case, the Deny effect means the deployment will be blocked.
You can assign this policy to a scope, like a resource group or subscription.
az policy assignment create --name "RestrictVMSize" --display-name "Restrict VM Sizes to Approved List" --policy "YOUR_POLICY_DEFINITION_ID" --scope "/subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RESOURCE_GROUP_NAME"
Replace YOUR_POLICY_DEFINITION_ID, YOUR_SUBSCRIPTION_ID, and YOUR_RESOURCE_GROUP_NAME with your actual values. Once assigned, any attempt to deploy a VM with a size not in the in array will fail with a clear error message.
The real power comes from understanding the effects. Deny is the strictest, preventing non-compliant resources from being created or updated. Audit will log non-compliance but won’t block the action, useful for identifying existing issues or for less critical rules. Append allows you to add fields to a resource during creation, like automatically tagging resources. Modify can change existing resource properties. DeployIfNotExists is for deploying a remediation resource if a non-compliant resource is found, like deploying a diagnostic setting. Immutable prevents a resource from being deleted or updated.
The mental model for Azure Policy involves three core components: Definitions, Assignments, and Effects. A Definition is the rule itself, like the JSON above. An Assignment is where and how you apply that definition – to which scope and with what parameters. The Effect is what happens when the rule is triggered. You can also group related definitions into Initiatives (also known as Policy Sets) to manage them more easily.
When you define a policy, you’re essentially writing a declarative statement about your desired state. Azure Policy then continuously evaluates your resources against these statements. If a resource doesn’t match the if condition, the specified effect is triggered. This evaluation happens at the time of resource creation or update, and also periodically for existing resources to catch drift.
Many people think of Azure Policy as purely a preventative measure, only useful for blocking bad deployments. However, its Audit and DeployIfNotExists effects are incredibly powerful for understanding your current state and for actively remediating compliance gaps without necessarily blocking all operations. For instance, you can audit for resources missing a specific tag, then use DeployIfNotExists to deploy a Logic App that adds the tag to any resource that triggers the audit.
The next step is often figuring out how to automate remediation for existing non-compliant resources that were created before your policy was in place.