Using Bicep to create an Azure Policy definition
Tags: bicep, azure, iac
Published: 2022-12-07 09:24:00

In this post I would like to show you how you can create an Azure Policy definition in your subscription using a Bicep template.

First of all, what is an Azure Policy?
Looking at the documentation ([here](https://learn.microsoft.com/en-us/azure/governance/policy/overview)), we find this definition:

> Azure Policy helps to enforce organizational standards and to assess compliance at-scale

Using Azure Policies, you can implement governance on your resources forcing some characteristics or properties on your resources.  

An Azure Policy is, basically, a JSON file like the following:

```json
{
    "properties": {
        "displayName": "Allow skus for App Service",
        "policyType": "Custom",
        "description": "This policy allows to define the permitted skus for the App Service instance",
        "mode": "Indexed",
        "metadata": {
            "category": "Web App"
        },
        "parameters": {
            "allowedSkus": {
                "type": "array",
                "metadata": {
                    "description": "The list of skus can be used for the App Service plan (e.g. Free or PremiumV3)",
                    "displayName": "Allowed skus"
                }
            }
        },
        "policyRule": {
            "if": {
                "allOf": [
                    {
                        "field": "type",
                        "equals": "Microsoft.Web/serverfarms"
                    },
                    {
                        "not": {
                            "field": "Microsoft.Web/serverfarms/sku.tier",
                            "in": "[parameters('allowedSkus')]"
                        }
                    }
                ]
            },
            "then": {
                "effect": "deny"
            }
        }
    }
}
```

This policy sample allow us check that all the App Service Plan resources we create will have one of the sku we set in the input parameters.

As you can see in the previous JSON, you have different sections in the policy definition.

### Policy Metadata
In this part of the policy definition, you can set the metadata for the policy, e.g. the name, the description and so on:

```json
"displayName": "Allow skus for App Service",
"policyType": "Custom",
"description": "This policy allows to define the permitted skus for the App Service instance",
"mode": "Indexed",
"metadata": {
    "category": "Web App"
},
```

Using these properties, you can set the display name, the description and the type of the policy. All these values will appear in the Azure portal when you or someone will use the policy.

### Policy parameters
This part of the definition allows you to pass values when you will assign the policy. You can assign the same definition with different parameters to different scope.

```json
"parameters": {
    "allowedSkus": {
        "type": "array",
        "metadata": {
            "description": "The list of skus can be used for the App Service plan (e.g. Free or PremiumV3)",
            "displayName": "Allowed skus"
        }
    }
},
```
In our sample, we declare a parameter called `allowedSkus`, its type is an array (you will pass value with the syntax `["Premium","Free"]`), and we define the appearance of the parameter in the portal (the `metadata` section).

### Policy rule
Basically, a Policy is an IF: is some condition is true, then you apply an effect.
In the policyRule part of the policy JSON, you can define the condition and the effect:

```json
"policyRule": {
    "if": {
        "allOf": [
            {
                "field": "type",
                "equals": "Microsoft.Web/serverfarms"
            },
            {
                "not": {
                    "field": "Microsoft.Web/serverfarms/sku.tier",
                    "in": "[parameters('allowedSkus')]"
                 }
            }
        ]
    },
    "then": {
        "effect": "deny"
    }
}
```
In our sample, if the type of the resource we are managing is `Microsoft.Web/serverfarms` (it is an App Service Plan) and the value of the `tier` property of the `sku` object is not in the value we passed in the parameter, then the effect is `deny`. 
Deny means that you canno create that resource, even if you are all the permissions!
More info about the affects you can use in a policy are available to this [link](https://learn.microsoft.com/en-us/azure/governance/policy/concepts/effects).

## Creating the template
Once you have the policy definition (the JSON), is easy to create a Bicep template that allows you to create the definition in your subscription.

```bicep
targetScope = 'subscription'

var policyDefinitionName = 'AllowSkusAppService'

resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2020-03-01' = {
  name: policyDefinitionName
  properties: {
    // Here you add the "bicepted" policy JSON 
  }
}
```

In the previous Bicep template, you can find the term "bicepted" that means you take the JSON of the policy and

- remove the char `"` before and after the property names,
- substitute the char `"` with the `'` in the values,
- remove the `,` at the end of the lines,
- use the `\'` instead `'` when you want to use `'` as part of the value,

and you have:

```bicep
targetScope = 'subscription'

var policyDefinitionName = 'AllowSkusAppService'

resource policyDefinition 'Microsoft.Authorization/policyDefinitions@2020-03-01' = {
  name: policyDefinitionName
  properties: {
    policyType: 'Custom' 
    mode: 'Indexed'
    description: 'This policy allows to define the permitted skus for the App Service instance'
    displayName: 'Allow skus for App Service'
    metadata: {
      category : 'WebApp'
    }
    parameters: {
      allowedSkus: {
        type: 'array'
        metadata: {
          description: 'The list of skus can be used for the App Service plan (e.g. Free or PremiumV3)'
          displayName: 'Allowed skus'
        }
      }
    }
    policyRule: {
      if: {
        allOf: [
            {
                field: 'type'
                equals: 'Microsoft.Web/serverfarms'
            }
            {
                not: {
                    field: 'Microsoft.Web/serverfarms/sku.tier'
                    in: '[parameters(\'allowedSkus\')]'
                }
            }
        ]
    }
      then: {
        effect: 'deny'
      }
    }
  }
}

```
 
To deploy the template and create the policy definition you can use the command:

```bash
az deployment sub create --location <your region> --template-file <templatename>.bicep
```