A little while back I spent an hour or so writing an Azure policy, only to discover that the Azure landing zones Terraform module already has a policy definition that does exactly what I wanted to accomplish, but no assignments linked to it. It took me another hour of confusion and frustration to figure out how to actually assign the policy, as there is a step I completely overlooked. So here is a quick summary of how to use these policies so you can save yourself the trouble.
Set the library_path
First off we need to make sure the library_path
variable is set to make sure the Azure landing zones-module can find our customizations. This is a requirement for adding custom landing zone archetypes, policy definitions, policy assignments etc.
First, create a new folder named lib in the root of your Terraform project. Then, in the main.tf-file, add the following line to your module block:
module "azure_landing_zones_architecture" {
source = "Azure/caf-enterprise_scale/azurerm"
version = "3.1.2"
library_path = "${path.root}/lib"
}
Create the policy assignment
Under the lib
-folder, create a new folder named policy_assignments
and add a new file named policy_assignment_<name of policy>.tf
. The Azure landing zones-module will pick up all files prefixed with policy_assignment_
, but the rest of the name is only important for your own mental health. Name if something useful and related to what the policy does.
In the example below I use the Deny vNet peering to non-approved vNets-policy to only allow spoke networks to peer with the hub network. You can see a complete list of policy definitions in GitHub
{
"name": "Restrict_VNet_Peering",
"type": "Microsoft.Authorization/policyAssignments",
"apiVersion": "2019-09-01",
"properties": {
"description": "This policy denies the creation of vNet Peerings to non-approved vNets under the assigned scope",
"displayName": "Deny vNet peering to non-approved vNets",
"notScopes": [],
"parameters": {},
"policyDefinitionId": "${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/Deny-VNET-Peering-To-Non-Approved-VNETs",
"scope": "${current_scope_resource_id}",
"enforcementMode": null,
"nonComplianceMessages": [
{
"message": "VNet peering to non-approved vNets is not allowed"
}
]
},
"location": "${default_location}",
"identity": {
"type": "SystemAssigned"
}
}
The important lines to change from my example are highlighted in the code block:
- name: The name used to reference the policy assignment from an archetype definition or archetype extension. Note that the max length is 24 characters
- description: A short description of what the policy does
- displayName: More human friendly name to make things easier to find the the Azure portal
- policyDefinitionId: The resource ID of the policy definition. A good practice is to keep most definitions in the root scope. Keep
${root_scope_resource_id}/providers/Microsoft.Authorization/policyDefinitions/
and append the string with the name of the policy definition you want to use - message: The message that will be displayed in the Azure portal if the policy is violated
Assign the policy
Finally, we need to actually assign the policy to a management group. We have two different options to achieve this:
- We can extend a built in archetype definition (e.g. "corp" or "online")
- We can create a custom landing zone archetype
In the example below I use the second option and create my own custom landing zone. You can follow the link to get a complete example on how this is created. The only difference from that example is the policy assignment in lib/archetype_definition_customer_online.json
:
{
"customer_online": {
"policy_assignments": [
"Restrict_VNet_Peering"
],
"policy_definitions": [],
"policy_set_definitions": [],
"role_definitions": [],
"archetype_config": {
"parameters": {},
"access_control": {}
}
}
}
We also have two different options for setting the policy parameters (i.e. the list of allowed virtual networks):
Create the list directly in our archetype definition/extension file
"parameters": {
"allowedVnets": {
"value": [
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-hub/providers/Microsoft.Network/virtualNetworks/vnet-hub"
]
}
}
Pass in the parameters in the terraform module
archetype_config = {
archetype_id = "customer_online"
parameters = {
Restrict_VNet_Peering = {
allowedVnets = [
data.azurerm_virtual_network.hub.id
]
}
}
}