Azure Policy pattern: deploy resources

The deployIfNotExists effect makes it possible to deploy an Azure Resource Manager template (ARM template) when creating or updating a resource that isn't compliant. This approach can be preferred to using the deny effect as it lets resources continue to be created, but ensures the changes are made to make them compliant.

Sample policy definition

This policy definition uses the field operator to evaluate the type of resource created or updated. When that resource is a Microsoft.Network/virtualNetworks, the policy looks for a network watcher in the location of the new or updated resource. If a matching network watcher isn't located, the ARM template is deployed to create the missing resource.

Note

This policy requires you have a resource group named NetworkWatcherRG in your subscription. Azure creates the NetworkWatcherRG resource group when you enable Network Watcher in a region.

{
    "properties": {
        "displayName": "Deploy network watcher when virtual networks are created",
        "mode": "Indexed",
        "description": "This policy creates a network watcher resource in regions with virtual networks. You need to ensure existence of a resource group named networkWatcherRG, which will be used to deploy network watcher instances.",
        "metadata": {
            "category": "Network"
        },
        "parameters": {},
        "policyRule": {
            "if": {
                "field": "type",
                "equals": "Microsoft.Network/virtualNetworks"
            },
            "then": {
                "effect": "DeployIfNotExists",
                "details": {
                    "type": "Microsoft.Network/networkWatchers",
                    "resourceGroupName": "networkWatcherRG",
                    "existenceCondition": {
                        "field": "location",
                        "equals": "[field('location')]"
                    },
                    "roleDefinitionIds": [
                        "/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7"
                    ],
                    "deployment": {
                        "properties": {
                            "mode": "incremental",
                            "template": {
                                "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
                                "contentVersion": "1.0.0.0",
                                "parameters": {
                                    "location": {
                                        "type": "string"
                                    }
                                },
                                "resources": [{
                                    "apiVersion": "2016-09-01",
                                    "type": "Microsoft.Network/networkWatchers",
                                    "name": "[concat('networkWacher_', parameters('location'))]",
                                    "location": "[parameters('location')]"
                                }]
                            },
                            "parameters": {
                                "location": {
                                    "value": "[field('location')]"
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Explanation

existenceCondition

"type": "Microsoft.Network/networkWatchers",
"resourceGroupName": "networkWatcherRG",
"existenceCondition": {
    "field": "location",
    "equals": "[field('location')]"
},

The properties.policyRule.then.details block tells Azure Policy what to look for related to the created or updated resource in the properties.policyRule.if block. In this example, a network watcher in the resource group networkWatcherRG must exist with field location equal to the location of the new or updated resource. Using the field() function allows the existenceCondition to access properties on the new or updated resource, specifically the location property.

roleDefinitionIds

"roleDefinitionIds": [
    "/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7"
],

The roleDefinitionIds array property in the properties.policyRule.then.details block tells the policy definition which rights the managed identity needs to deploy the included Resource Manager template. This property must be set to include roles that have the permissions needed by the template deployment, but should use the concept of 'principle of least privilege' and only have the needed operations and nothing more.

Deployment template

The deployment portion of the policy definition has a properties block that defines the three core components:

  • mode - This property sets the deployment mode of the template.

  • template - This property includes the template itself. In this example, the location template parameter sets the location of the new network watcher resource.

    "template": {
        "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
        "contentVersion": "1.0.0.0",
        "parameters": {
            "location": {
                "type": "string"
            }
        },
        "resources": [{
            "apiVersion": "2016-09-01",
            "type": "Microsoft.Network/networkWatchers",
            "name": "[concat('networkWacher_', parameters('location'))]",
            "location": "[parameters('location')]"
        }]
    },
    
  • parameters - This property defines parameters that are provided to the template. The parameter names must match what are defined in template. In this example, the parameter is named location to match. The value of location uses the field() function again to get the value of the evaluated resource, which is the virtual network in the policyRule.if block.

    "parameters": {
        "location": {
            "value": "[field('location')]"
        }
    }
    

Next steps