Policy as Code (PoC): Deploying and Managing Azure Policy in Bicep

What is Azure Policy ? As Per Official Microsoft Article


Understand evaluation outcomes

  • A resource is created or updated in a scope with a policy assignment.
  • A policy or initiative is newly assigned to a scope.
  • A policy or initiative already assigned to a scope is updated.
  • During the standard compliance evaluation cycle, which occurs once every 24 hours.

Control the response to an evaluation

  • Deny the resource change
  • Log the change to the resource
  • Alter the resource before the change
  • Alter the resource after the change
  • Deploy related compliant resources

Remediate non-compliant resources

Azure Policy vs Azure RBAC

Azure Policy Objects

Policy definition

Initiative definition


Going through the Bicep code

  • The main.bicep calls the policy.bicep file.
  • The policy.bicep in returns calls the modules in modules/policies directory and creates the policies.
  • The main.parameters.json file is passed to the command which contains all the key value pair of the variables. You need to exchange “” with your values.

Understanding Policy code

targetScope = 'subscription'
param policyInitiativeArray array
module policyM 'modules/policy.bicep' = [for (pol, i) in policyInitiativeArray: {
name: 'Policy-${i}'
params: {
policyData: pol
module allowedRegionsModule './policies/allowed_regions.bicep' = {
name: '${policyData.client}-${policyData.allowed_regions_policy.name}'
params: {
client: policyData.client
policyInputData: policyData.allowed_regions_policy
targetScope = 'subscription'param policyInputData object
param client string
output policyId string = allowed_regions_policy.id
resource allowed_regions_policy 'Microsoft.Authorization/policyDefinitions@2021-06-01' = {
name: '${client}-${policyInputData.name}'
properties: {
displayName: '${client}-${policyInputData.displayName}'
policyType: 'Custom'
mode: 'All'
description: policyInputData.description
metadata: {
category: 'General'
policyRule: {
if: {
allOf: [
field: 'location'
notIn: '[parameters(\'regAllowedRegions\')]'
field: 'location'
notEquals: 'global'
field: 'type'
notEquals: 'Microsoft.AzureActiveDirectory/b2cDirectories'
then: {
effect: policyInputData.effect
resource policyDefSet 'Microsoft.Authorization/policySetDefinitions@2021-06-01' = {
name: '${policyData.client}-${policyData.name}'
dependsOn: [
properties: {
policyType: policyData.policyType
displayName: policyData.policySetDefinitionDisplayName
parameters: {}
policyDefinitions: [
policyDefinitionId: allowedRegionsModule.outputs.policyId
parameters: {}
resource policyAssign 'Microsoft.Authorization/policyAssignments@2021-06-01' = {
name: '${policyData.client}-${policyData.name}-Assignment'
properties: {
displayName: '${policyData.client}-${policyData.policyInitiativeDisplayName}'
enforcementMode: 'Default'
policyDefinitionId: policyDefSet.id
parameters: {}
"allowed_regions_policy": {
"name": "Allowed-Azure-Regions",
"displayName": "Allowed Azure Regions",
"description": "This policy allows resources to be created in the allowed locations.",
"listOfAllowedLocations": ["canadaeast", "canadacentral"],
"effect": "Audit"

Policies that are created

  1. Allowed Regions
  2. Allowed Resource Types
  3. Allowed SQL Version
  4. Allowed Storage Account SKU
  5. Allowed VM Extensions
  6. Allowed Subnets for Public IP
  7. Allowed VM OS and version
  8. Allowed VM SKU
  9. DDOS Protection
  10. Diagnostics Settings
  11. Diagnostic settings logs to be send to Log Analytics WOrkspace
  12. Firewall Internet Traffic
  13. Key Vault Purge Protection
  14. Key Vault soft delete
  15. VM NIC IP Forwarding
  16. Enable Network Watchers
  17. NSG for every Subnet
  18. NSG Inbound rules
  19. SQL Database Private endpoint
  20. SQL Database TLS version
  21. SQL server public network access
  22. Storage Account Secure Transfer Settings
  23. Storage Account Key Expiry
  24. Storage Account Network Access
  25. Mandatory Tags
  26. Optional Tags
  27. Internet facing VM NSG
  28. VM managed disk
  29. VM management port
  30. VM encryption

Run the code

Authenticate Azure CLI

Trigger Manually




Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

A Gentle Introduction to Dependency Injection

Dynamic Jenkins Slave

Kendis Scaling Agile Solution

Kendis AI based weekly scope change Reports

Nrwl Continues to Evolve and Grow as NgRx and React Experts Join the Team

Slot Machine Noises Free

Slot Machine Noises Free

2.5D Platformer: Level Design Update

Flutter Stack Weekly — Issue #16

Using Maven’s setting.xml server credentials in Gradle

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Arlan Nugara

Arlan Nugara

More from Medium

💪Deploy VM-Series Next-Generation Firewall from Palo Alto Networks using Bicep Language

How to delete the contents of an Azure Storage Account within an Azure DevOps Pipeline

Azure Portal Blade for generation a Storage connection string

Agile Security Framework

Azure Storage, terraform and a tale of 404 StorageAccountNotFound