You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过本地JSON文件在Terraform中创建Azure PolicyDefinition并解决报错?

解决Terraform创建Azure策略定义时的JSON解析错误

问题场景

使用以下Terraform代码创建Azure策略定义:

resource "azurerm_policy_definition" "name-caf-alz-policy-sandbox-denyvnetpeering" {
  name                = "Audit-AzureHybridBenefit"
  display_name        = "未使用资源导致成本浪费应避免"
  description         = "通过启用Azure混合权益优化成本。使用此策略定义作为成本控制手段,识别未使用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
}

在Azure DevOps中执行时,terraform validate、init、plan步骤均正常,但执行terraform apply时抛出错误:

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'.'."

将policy_rule修改为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 {}

注:该JSON文件通过Azure GUI创建策略定义时可正常使用。

错误原因

  1. 第一个错误:使用的JSON文件是完整的Azure策略定义结构(包含apiVersion、properties等外层字段),但Terraform的azurerm_policy_definition资源的policy_rule参数只需要策略规则本身(即原JSON中properties.policyRule对应的内容)。Azure API收到包含apiVersion的规则内容时,会判定为无效格式。
  2. 第二个错误:file()函数已经将JSON文件读取为字符串,再用jsonencode()会对字符串进行二次编码,导致结果是一个JSON字符串,而Terraform期望policy_rule是map[string]interface{}类型,因此无法反序列化。

解决方案

方案1:通过Terraform代码提取规则内容

使用jsondecode()解析JSON文件,直接提取其中的policyRule部分:

resource "azurerm_policy_definition" "name-caf-alz-policy-sandbox-denyvnetpeering" {
  name                = "Audit-AzureHybridBenefit"
  display_name        = "未使用资源导致成本浪费应避免"
  description         = "通过启用Azure混合权益优化成本。使用此策略定义作为成本控制手段,识别未使用AHUB的虚拟机。"
  mode                = "All"
  policy_type         = "Custom"                                           
  policy_rule         = jsondecode(file("${path.module}/lib/policy_definitions/policy_definition_es_deny_vnet_peer_cross_sub.json")).properties.policyRule
  management_group_id = data.azurerm_management_group.namemgmtgroup.id
}

(注意:原JSON的结构是外层properties下包含policyRule,所以需要.properties.policyRule来定位)

方案2:修改JSON文件,仅保留规则内容

编辑JSON文件,删除外层的apiVersion、name、properties等字段,只保留policyRule对应的JSON对象。修改后的JSON示例:

{
  "if": {
    "allOf": [
      {
        "field": "type",
        "equals": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings"
      },
      {
        "not": {
          "field": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings/remoteVirtualNetwork.id",
          "contains": "[subscription().id]"
        }
      }
    ]
  },
  "then": {
    "effect": "deny"
  }
}

之后Terraform代码可以继续使用file()函数直接读取:

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

内容的提问来源于stack exchange,提问作者Xyltic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 05:25:35