Passing the array to Azure policy Parameters

Hi There,

I am trying to pass the list of string to the Parameters value of the azurerm_policy_assignment here is the code:

resource “azurerm_policy_definition” “policy” {
name = var.policy_name
policy_type = var.policy_type
mode = var.policy_mode
display_name = var.display_name

metadata = <<METADATA
{
“category”: “General”
}

METADATA

policy_rule = <<POLICY_RULE
{
“if”: {
“not”: {
“field”: “location”,
“in”: “[parameters(‘allowedLocations’)]”
}
},
“then”: {
“effect”: “[parameters(‘effect’)]”
}
}
POLICY_RULE

parameters = <<PARAMETERS
{
“allowedLocations”: {
“type”: “Array”,
“metadata”: {
“description”: “The list of allowed locations for resources.”,
“displayName”: “Allowed locations”,
“strongType”: “location”
}
},
“effect”: {
“type”: “string”,
“metadata”: {
“description”: “Provide the list of the effect that will take place”,
“displayName”: “Allowed effect that should take place”
},
“allowedValues”: [
“Audit”,
“Deny”,
“Disabled”
]
}
}
PARAMETERS

}

resource “azurerm_policy_assignment” “policy_assignment” {
name = var.policy_assignment_name
scope = var.policy_scope
policy_definition_id = azurerm_policy_definition.policy.id
description = var.policy_description
display_name = var.policy_assignment_name

parameters = <<PARAMETERS
{
“allowedLocations”: {
“value”: “{var.allowedLocations}" }, "effect": { "value": "{var.policy_effect}”
}
}
PARAMETERS

}

but I am getting the error as shown below.


Error: Invalid template interpolation value

on Modules/AzurePolicy/main.tf line 69, in resource “azurerm_policy_assignment” “policy_assignment”:
65:
66:
67:
68:
69: “${var.allowedLocations}”
70:
71:
72:
73:
74:
75:
76:
|----------------
| var.allowedLocations is list of string with 4 elements

Cannot include the given value in a string template: string required.

Do you know if I am doing something wrong here or if there is a way to do something like this.

Hi @Chirag1233,

This error is appearing because you are constructing a JSON string using string interpolation, and so Terraform requires you to convert all of your values to strings in some way.

However, an easier answer is to stop using string templates and use Terraform’s jsonencode function instead: that way the result is guaranteed to be valid JSON and Terraform will convert all of the values you supply to JSON syntax automatically.

Unfortunately I can’t see exactly what you tried already because your example isn’t marked as code and so the forum has misunderstood it. However, I think the following will be equivalent to what you were trying in the azurerm_policy_assignment.policy_assignment block:

  parameters = jsonencode({
    "allowedLocations": {
      "value": var.policy_effect,
    },
  })

The jsonencode function will translate the given value to JSON using the type mapping table shown in its documentation, which will produce the following JSON if var.policy effect were set to "example":

{
  "allowedLocations": {
    "value" "example"
  }
}

If you translate all of the JSON templates in your configuration to be jsonencode calls instead then you’ll be able to include values of all types in your values, and have them encoded to JSON automatically.

thanks a lot for your help.

I am still having the issue i might give you this in more details so that you can point me to the right direction.
Here is the code

main.tf file.

locals {
  policylocation = jsonencode(var.allowedLocations)
}

resource "azurerm_policy_definition" "policy" {
  name         = var.policy_name
  policy_type  = var.policy_type
  mode         = var.policy_mode
  display_name = var.display_name

  metadata = <<METADATA
    {
    "category": "General"
    }


METADATA


  policy_rule = <<POLICY_RULE
    {
    "if": {
      "not": {
        "field": "location",
        "in": "[parameters('allowedLocations')]"
      }
    },
    "then": {
      "effect": "[parameters('effect')]"
    }
  }
POLICY_RULE


  parameters = <<PARAMETERS
    {
    "allowedLocations": {
      "type": "Array",
      "metadata": {
        "description": "The list of allowed locations for resources.",
        "displayName": "Allowed locations",
        "strongType": "location"
      }
    },
     "effect": {
      "type": "string",
      "metadata": {
        "description": "Provide the list of the effect that will take place",
        "displayName": "Allowed effect that should take place"
      },
    "allowedValues": [
            "Audit",
            "Deny",
            "Disabled"
        ]
    }
  }
PARAMETERS

}

resource "azurerm_policy_assignment" "policy_assignment" {
  name                 = var.policy_assignment_name
  scope                = var.policy_scope
  policy_definition_id = azurerm_policy_definition.policy.id
  description          = var.policy_description
  display_name         = var.policy_assignment_name

  parameters = <<PARAMETERS
{
  "allowedLocations": {
    "value": "${var.allowedLocations}"
  },
    "effect": {
    "value": "${var.policy_effect}"
  }
}
PARAMETERS

}

Variable.tf

variable "policy_name" {
    type = string
}

variable "display_name" {
    type = string
}

variable "policy_assignment_name" {
    type = string
}

variable "allowedLocations" {
    type = list
}

variable "policy_description" {
    type = string
  default = "Policy Assignment created via an Acceptance Test"
}

variable "policy_scope" {
    type = string
}

variable "policy_type" {
    type = string
  default = "Custom"
}

variable "policy_mode" {
    type = string
  default = "Indexed"
}

variable "policy_effect" {
    type = string
  default = "Audit"
}

Here’s a version of what you shared with all of the string templates replaced with calls to jsonencode like I was recommending in my earlier comment.

variable "allowed_locations" {
  type = list(string)
}

variable "policy_effect" {
  type = string
}

resource "azurerm_policy_definition" "policy" {
  name         = var.policy_name
  policy_type  = var.policy_type
  mode         = var.policy_mode
  display_name = var.display_name

  metadata = jsonencode({
    "category": "General",
  })

  policy_rule = jsonencode({
    "if": {
      "not": {
        "field": "location",
        "in": "[parameters('allowedLocations')]",
      },
    },
    "then": {
      "effect": "[parameters('effect')]",
    },
  })

  parameters = jsonencode({
    "allowedLocations": {
      "type": "Array",
      "metadata": {
        "description": "The list of allowed locations for resources.",
        "displayName": "Allowed locations",
        "strongType": "location",
      },
    },
     "effect": {
      "type": "string",
      "metadata": {
        "description": "Provide the list of the effect that will take place",
        "displayName": "Allowed effect that should take place",
      },
      "allowedValues": [
        "Audit",
        "Deny",
        "Disabled",
      ],
    },
  })
}

resource "azurerm_policy_assignment" "policy_assignment" {
  name                 = var.policy_assignment_name
  scope                = var.policy_scope
  policy_definition_id = azurerm_policy_definition.policy.id
  description          = var.policy_description
  display_name         = var.policy_assignment_name

  parameters = jsonencode({
    "allowedLocations": {
      "value": var.allowed_locations,
    },
    "effect": {
      "value": var.policy_effect,
    },
  })
}

In particular notice the parameters of azurerm_policy_assignment.policy_assignment where we can just refer directly to var.allowed_locations and var.policy_effect without any special transforming, because jsonencode knows it should convert a Terraform list into a JSON array and a Terraform string into a JSON string.

Thanks a lot @apparentlymart I was doing it wrong now it working. :slight_smile: