Search code examples
azureterraformterraform-provider-azure

How to create in Terraform Azure PolicyDefinition with local JSON-file?


I want to create an Azure PolicyDefinition and I am using the code below:

resource "azurerm_policy_definition" "name-caf-alz-policy-sandbox-denyvnetpeering" {
  name                = "Audit-AzureHybridBenefit"
  display_name        = "Unused resources driving cost should be avoided"
  description         = "Optimize cost by enabling Azure Hybrid Benefit. Leverage this Policy definition as a cost control to reveal Virtual Machines not using AHUB."
  mode                = "All"
  policy_type         = "Custom"                                           
  policy_rule         = file("${path.module}/lib/policy_definitions/policy_definition_es_deny_vnet_peer_cross_sub.json")
  management_group_id = data.azurerm_management_group.namemgmtgroup.id
}

When I run this command via Azure DevOps, Terraform Validate, Init, and Plan are working but when I do Terraform Apply I get this error:

creating/updating Policy Definition "Audit-AzureHybridBenefit": policy.DefinitionsClient#CreateOrUpdateAtManagementGroup: Failure responding to request: StatusCode=400 -- Original Error: autorest/azure: Service returned an error. Status=400 Code="InvalidPolicyRule" Message="Failed to parse policy rule: 'Could not find member 'apiVersion' on object of type 'PolicyRuleDefinition'. Path 'apiVersion'.'."

When I change the policy_rule to

jsonencode(file("${path.module}/lib/policy_definitions/policy_definition_es_deny_vnet_peer_cross_sub.json"))

Error: expanding JSON for policy_rule: JSON: cannot unmarshal string into Go value of type map[string]interface {}

The JSON-file itself works succesfully when creating it via the GUI.

JSON-file itself can be found at

https://github.com/Azure/Enterprise-Scale/blob/main/src/resources/Microsoft.Authorization/policyDefinitions/Deny-VNET-Peer-Cross-Sub.json


Solution

  • The issue indicates that the Apiversion property, which is present in the Json file path you provided, is incompatible. The Structure of Policy defintion Json as specified in this Doc should not always include the apiversion property.

    To verify the issue properly, I've tried adding the Json policy in the policy rule of .tf file and it worked as expected as shown.

    provider "azurerm"{
    features{}
    }
    resource "azurerm_policy_definition" "name-caf-alz-policy-sandbox-denyvnetpeering" {
      name                = "Audit-AzureHybridBenefit"
      display_name        = "Unused resources driving cost should be avoided"
      description         = "Optimize cost by enabling Azure Hybrid Benefit. Leverage this Policy definition as a cost control to reveal Virtual Machines not using AHUB."
      mode                = "All"
      policy_type         = "Custom"                                           
      policy_rule         = <<POLICY_RULE
      {
          "if": {
            "allOf": [
              {
                "field": "type",
                "equals": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings"
              },
              {
                "field": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings/remoteVirtualNetwork.id",
                "notcontains": "[[subscription().id]"
              }
            ]
          },
          "then": {
            "effect": "[[parameters('effect')]"
          }
        }
        POLICY_RULE   
      }
    

    As you are not using parameters in the Policy, I have not included the parameters block below. If required, you may add it to the policyrule with the following structure to make it work.

    parameters =  <<PARAMETERS
         {
         "effect": {
            "type": "String",
            "metadata": {
              "displayName": "Effect",
              "description": "Enable or disable the execution of the policy"
            },
            "allowedValues": [
              "Audit",
              "Deny",
              "Disabled"
            ],
            "defaultValue": "Deny"
          }
        }
        PARAMETERS
    

    Executed terraform init and validated the configuration using terraform validate:

    enter image description here

    Executed terraform apply:

    enter image description here

    Created policy definition successfully in the Portal:

    enter image description here

    Or

    if you only want to work with file(path) function, you don't need to include jsonencode function because the policy_rule input to the azurerm_policy_definition resource should be a map representing the JSON structure, not a string. Make sure the syntax and path has correctly given.