10 – Azure Policy and Governance – Terraform Mini Project

Table of Contents

  1. Step 1 – Create Resource Group and Base Terraform Setup
  2. Step 2 – Create Mandatory Tag Policy
  3. Step 3 – Create Allowed VM Size Policy
  4. Step 4 – Create Allowed Location Policy
  5. Final Outcome of This Mini Project

In this mini project, we implement Azure governance using Terraform. The goal is to enforce organizational standards at the subscription level using Azure Policy—so that resources follow rules for:

  • Mandatory tags
  • Allowed VM sizes
  • Allowed deployment locations

Everything is automated using Terraform infrastructure as code.


Step 1 – Create Resource Group and Base Terraform Setup

We start by creating:

  • A resource group
  • Variables for locations, VM sizes, and allowed tags
  • Output to display current subscription ID

Resource Group – rg.tf

resource "azurerm_resource_group" "rg" {
  name     = "rgminipro7878"
  location = "Central US"
}

Read Current Subscription – main.tf

data "azurerm_subscription" "subscriptioncurrent" {}

Output Subscription ID – output.tf

output "subscription_id" {
  value = data.azurerm_subscription.subscriptioncurrent.id
}

Variables – variables.tf

variable "location" {
  type    = list(string)
  default = ["eastus", "westus"]
}

variable "vm_sizes" {
  type    = list(string)
  default = ["Standard_B2s", "Standard_B2ms"]
}

variable "allowed_tags" {
  type    = list(string)
  default = ["department", "project"]
}

After running:

terraform apply

✔ Resource group was created
✔ Subscription ID output was verified


Step 2 – Create Mandatory Tag Policy

Next, we enforce that every resource must contain two tags:

  • department
  • project

If either tag is missing → resource creation is denied.

Policy Definition – policy1.tf

resource "azurerm_policy_definition" "tagpolicy" {

  name         = "allowed-tag"
  policy_type  = "Custom"
  mode         = "All"
  display_name = "Allowed tags policy"

  policy_rule = jsonencode({
    if = {
      anyOf = [
        {
          field  = "tags[${var.allowed_tags[0]}]"
          exists = false
        },
        {
          field  = "tags[${var.allowed_tags[1]}]"
          exists = false
        }
      ]
    }

    then = {
      effect = "deny"
    }
  })
}

Assign Policy to Subscription

resource "azurerm_subscription_policy_assignment" "tag_assign" {

  name = "tag-assignment"

  policy_definition_id = azurerm_policy_definition.tagpolicy.id

  subscription_id = data.azurerm_subscription.subscriptioncurrent.id
}

⚠ Important
To create and assign policies, your account must have:
Resource Policy Contributor role.

Testing the Policy – testrg.tf

resource "azurerm_resource_group" "bad" {
  name     = "bad-rg"
  location = "Central US"

  tags = {
    department = "IT"
    project    = "Demo"
  }
}

✔ Without tags → RG creation blocked
✔ With tags → RG creation allowed


Step 3 – Create Allowed VM Size Policy

Now we restrict which VM sizes can be used.

Allowed sizes:

  • Standard_B2s
  • Standard_B2ms

Policy Definition – policy2.tf

resource "azurerm_policy_definition" "vm_size" {

  name         = "vm-size"
  policy_type  = "Custom"
  mode         = "All"
  display_name = "Allowed vm policy"

  policy_rule = jsonencode({
    if = {
      field = "Microsoft.Compute/virtualMachines/sku.name"

      notIn = [
        var.vm_sizes[0],
        var.vm_sizes[1]
      ]
    }

    then = {
      effect = "deny"
    }
  })
}

Assign VM Size Policy

resource "azurerm_subscription_policy_assignment" "vm_assign" {

  name = "size-assignment"

  policy_definition_id = azurerm_policy_definition.vm_size.id

  subscription_id = data.azurerm_subscription.subscriptioncurrent.id
}

✔ Any VM outside allowed list → blocked
✔ Governance enforced at subscription level


Step 4 – Create Allowed Location Policy

Finally, we restrict deployments only to:

  • eastus
  • westus

Policy Definition – policy3.tf

resource "azurerm_policy_definition" "location" {

  name         = "location"
  policy_type  = "Custom"
  mode         = "All"
  display_name = "Allowed location policy"

  policy_rule = jsonencode({
    if = {
      field = "location"

      notIn = [
        var.location[0],
        var.location[1]
      ]
    }

    then = {
      effect = "deny"
    }
  })
}

Assign Location Policy

resource "azurerm_subscription_policy_assignment" "loc_assign" {

  name = "location-assignment"

  policy_definition_id = azurerm_policy_definition.location.id

  subscription_id = data.azurerm_subscription.subscriptioncurrent.id
}

✔ Resources in other regions → denied
✔ Standardized deployment geography


Final Outcome of This Mini Project

Using Terraform + Azure Policy we achieved:

✔ Mandatory tagging for all resources
✔ Standard VM sizes enforced
✔ Controlled allowed regions
✔ Governance at subscription level
✔ Fully automated with IaC

This approach is ideal for:

  • Enterprise governance
  • Cost control
  • Security compliance
  • Standardization across teams

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

TechMilestoneHub

Build Skills, Unlock Milestones

This is a test – edited from front page