Search code examples
jsonazureterraformtagsazure-policy

Create Azure policy with Terraform


I am trying to create an azure policy with terraform to add tags to resources. I want all the resources to inherit the resource group tags.

I've been following documentations and examples here and there but I can't figure out how to have the tags being assigned on the resources.

I think I am close, I do not want to write the tags in every single resources this is not sustainable.

My code is separated in 3 different files:

main.tf

terraform {
  
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = "=3.37.0"
    }
    azuread = {
      source  = "hashicorp/azuread"
      version = "2.31.0"
    }
  }
}

provider "azurerm" {
    subscription_id = var.azure_subscription_id
    tenant_id = var.azure_tenant_id
  features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
  }
}

#create azure resource group
resource "azurerm_resource_group" "rg" {
  name     = var.azure_rg_name
  location = var.azure_resource_group_location
  tags = {
    costcenter = var.azure_costcenter
    projectcode = var.azure_project_code
    environment = var.azure_env_code
    client = var.azure_client_code

  }
}
#Create azure storage account
resource "azurerm_storage_account" "sa" {
  name                     = lower("${var.azure_project_code}${var.azure_env_code}sa01")
  resource_group_name      = azurerm_resource_group.rg.name
  location                 = var.azure_resource_group_location
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

#Create container in previously created sa
resource "azurerm_storage_container" "ctnr2" {
  name                  = lower("${var.azure_project_code}${var.azure_env_code}tfstate01")
  storage_account_name  = azurerm_storage_account.sa.name
  container_access_type = "private"
}

#create azure policy definition
resource "azurerm_policy_definition" "az_pol_def" {
  name         = "Append a tag and its value to resources"
  policy_type  = "Custom"
  mode         = "Indexed"
  display_name = "Append a tag and its value to resources"

  metadata = jsonencode({
    "version" : "1.0.1",
    "category" : "Tags  "
    }
  )
  

  policy_rule = jsonencode({
      "if": {
        "field": "[concat('tags[', parameters('tagName'), ']')]",
        "exists": "false"
      },
      "then": {
        "effect": "append",
        "details": [
          {
            "field": "[concat('tags[', parameters('tagName'), ']')]",
            "value": "[parameters('tagValue')]"
          }
        ]
      } 
  })
}
#assign azure policy created previously
resource "azurerm_resource_group_policy_assignment" "az_pol_assign" {
  name                 = "Append a tag and its value to resources"
  resource_group_id    = azurerm_resource_group.rg.id
  policy_definition_id = azurerm_policy_definition.az_pol_def.id

  parameters = jsonencode({
    "parameters": {
      "tagName": {
        "type": "String",
        "metadata": {
          "displayName": "Tag Name",
          "description": "Name of the tag, such as 'environment'"
        }
      },
      "tagValue": {
        "type": "String",
        "metadata": {
          "displayName": "Tag Value",
          "description": "Value of the tag, such as 'production'"
        }
      }
    },
  })
}

variable.tf

variable "azure_resource_group_location" {
  default = "west europe"
  description   = "Location of the resource group."
}

variable "azure_subscription_id" {
  type        = string
  description = "Azure Subscription Id"
}

variable "azure_tenant_id" {
  type        = string
  description = "Azure Tenant Id"
}

variable "azure_rg_name" {
  type        = string
  description = "Azure Resource Group Name"
}

variable "azure_costcenter" {
  type        = string
  description = "Azure Tag Cost Center"
}

variable "azure_client_code" {
  type        = string
  description = "Azure Tag Client"
}

variable "azure_project_code" {
  type        = string
  description = "Azure Tag Project Code"
}

variable "azure_env_code" {
  type        = string
  description = "Azure Tag Environment Code"
}

resource_group_name.tfvars

#Azure tenant id
azure_tenant_id ="********-****-****-****-************"
#Azure subscription
azure_subscription_id = "********-****-****-****-************"
#Azure resource group location
azure_resource_group_location = "west europe"
#Azure RG name
azure_rg_name = "resource_group_name"
#Azure tag
azure_costcenter = "missions"
#Azure tag project code
azure_project_code = "test_project"
#Azure tag client code
azure_client_code = "leanne"
#Environement tag code :
azure_env_code="dev"

I understand that "parameter_values" should be used for my tags, but I'm not sure how?

Here's an error message which might help. error message

Any help would be much appreciated.

Thanks in advance !


Solution

  • You declared the policy parameters in the policy assignment (az_pol_assign).
    Instead you should declare the parameters in the policy definition (az_pol_def).

    In your policy assignment you can then set the values that you want to pass as parameters:

    #assign azure policy created previously
    resource "azurerm_resource_group_policy_assignment" "az_pol_assign" {
      name                 = "Append a tag and its value to resources"
      resource_group_id    = azurerm_resource_group.rg.id
      policy_definition_id = azurerm_policy_definition.az_pol_def.id
    
      parameters = jsonencode({
        tagName = {
          value = "environment"
        },
        tagValue = {
          value = "production"
        }
      })
    }
    

    NOTE When you use jsonencode() you don't need to use plain JSON, you can use the simpler HashiCorp configuration language (HCL) syntax as I did in my example.