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

如何在Terraform for_each循环内获取资源ID配置Azure防火墙规则

Terraform引用Azure IP组到防火墙规则报错解决方案

问题复现

使用Terraform创建Azure防火墙网络规则时,规则集合需要引用已创建的ipg_onpremiseIP组,直接在配置中传入IP组字符串名称时,部署触发如下报错:

Error: creating/updating Network Rule Collection "onprem-hub" in Firewall "fw_shared" (Resource Group "rg-shared"): network.AzureFirewallsClient#CreateOrUpdate: Failure sending request: StatusCode=400 -- Original Error: Code="AzureIpGroupsInvalidResourceId" Message="The resourceId ipg_onpremise is an invalid resourceId of an IpGroup." Details=[]

涉及的原始配置如下:
firewall.tf 核心配置:

resource "azurerm_firewall_network_rule_collection" "nrc_fw_shared_onprem_hub" {
  name                = "onprem-hub"
  azure_firewall_name = azurerm_firewall.fw_shared.name
  resource_group_name = azurerm_resource_group.rg_shared.name
  priority            = var.nrc_fw_shared_onprem_hub_rule_priority
  action              = var.nrc_fw_shared_onprem_hub_rule_action

  dynamic "rule" {
    for_each = var.nrc_fw_shared_onprem_hub_rules
    content {
        name                  = rule.value.name
        description           = lookup(rule.value, "description", null)
        source_addresses      = lookup(rule.value, "source_addresses", null)
        source_ip_groups      = lookup(rule.value, "source_ip_groups" , null)
        destination_addresses = lookup(rule.value, "destination_addresses", null)
        destination_ip_groups = lookup(rule.value, "destination_ip_groups", null)
        destination_ports     = lookup(rule.value, "destination_ports", null)
        protocols             = lookup(rule.value, "protocols", null)
    }
  }
}

resource "azurerm_ip_group" "ipg_onpremise" {
  name                = "ipg-onpremise"
  location            = azurerm_resource_group.rg_shared.location
  resource_group_name = azurerm_resource_group.rg_shared.name

  cidrs = var.ipg_onpremise_cidrs
}

terraform.tfvars 核心配置:

nrc_fw_shared_onprem_hub_rules = [
    {    
        name                  = "onprem->hub"
        source_addresses      = []
        destination_addresses = ["10.0.0.0/16"]
        destination_ports     = ["*"]
        protocols             = ["Any"]
        source_ip_groups      = ["ipg_onpremise"]
        destination_ip_groups = []
    },
]

根本原因

Azure RM Terraform提供程序中,防火墙规则的source_ip_groups、destination_ip_groups字段仅接受IP组的完整Azure资源ID作为合法入参,不支持直接传入IP组名称。当前配置在tfvars中传入的是字符串形式的IP组自定义名称,不符合API参数要求,因此触发资源ID无效报错。
额外注意:当前配置中声明的IP组资源实际命名为ipg-onpremise(中划线分隔),tfvars中写的ipg_onpremise是下划线分隔的自定义标识,和资源实际名称不匹配,后续做名称映射时需要注意对齐。

可行实现方案

根据IP组是否在当前Terraform配置中管理,分两类场景处理:

场景1:IP组由当前Terraform配置管理

即当前场景,IP组资源已经在同一份配置中声明,Terraform会自动为该资源导出id属性,属性值就是符合格式要求的完整资源ID,无需手动拼接。由于Terraform不会自动将变量中传入的字符串解析为对应资源引用,可选择以下两种改法:

  • 改法1:固定引用(适合IP组引用关系固定的场景)
    不需要在tfvars中传递IP组名称,直接在动态规则块中引用资源ID,给规则增加一个布尔类型的标记位控制是否启用该IP组即可。
    调整动态块逻辑:
    dynamic "rule" {
      for_each = var.nrc_fw_shared_onprem_hub_rules
      content {
          name                  = rule.value.name
          description           = lookup(rule.value, "description", null)
          source_addresses      = lookup(rule.value, "source_addresses", null)
          source_ip_groups      = lookup(rule.value, "use_onprem_source_ipg", false) ? [azurerm_ip_group.ipg_onpremise.id] : lookup(rule.value, "source_ip_groups" , null)
          destination_addresses = lookup(rule.value, "destination_addresses", null)
          destination_ip_groups = lookup(rule.value, "destination_ip_groups", null)
          destination_ports     = lookup(rule.value, "destination_ports", null)
          protocols             = lookup(rule.value, "protocols", null)
      }
    }
    
    对应调整tfvars规则配置:
    nrc_fw_shared_onprem_hub_rules = [
        {    
            name                  = "onprem->hub"
            source_addresses      = []
            destination_addresses = ["10.0.0.0/16"]
            destination_ports     = ["*"]
            protocols             = ["Any"]
            use_onprem_source_ipg = true
            destination_ip_groups = []
        },
    ]
    
  • 改法2:名称映射(适合需要灵活引用多个同配置IP组的场景)
    通过本地值维护IP组自定义名称到资源ID的映射关系,在动态块中自动将变量传入的名称转换为对应ID,不需要改动现有tfvars的结构。
    首先在配置中添加本地值映射:
    locals {
      ip_group_id_map = {
        "ipg_onpremise" = azurerm_ip_group.ipg_onpremise.id
        # 后续新增同配置管理的IP组,可在此处追加映射关系
      }
    }
    
    再调整动态块中IP组字段的赋值逻辑:
    dynamic "rule" {
      for_each = var.nrc_fw_shared_onprem_hub_rules
      content {
          name                  = rule.value.name
          description           = lookup(rule.value, "description", null)
          source_addresses      = lookup(rule.value, "source_addresses", null)
          source_ip_groups      = [for ipg_name in lookup(rule.value, "source_ip_groups" , []) : local.ip_group_id_map[ipg_name]]
          destination_addresses = lookup(rule.value, "destination_addresses", null)
          destination_ip_groups = [for ipg_name in lookup(rule.value, "destination_ip_groups" , []) : local.ip_group_id_map[ipg_name]]
          destination_ports     = lookup(rule.value, "destination_ports", null)
          protocols             = lookup(rule.value, "protocols", null)
      }
    }
    

场景2:IP组不在当前Terraform配置中管理

如果要引用的IP组是提前创建、由其他配置或人工管理的资源,不要硬编码完整资源ID,通过azurerm_ip_group数据源查询获取资源ID即可:

data "azurerm_ip_group" "ipg_onpremise" {
  name                = "ipg-onpremise"
  resource_group_name = "rg-shared"
}

后续在规则中引用data.azurerm_ip_group.ipg_onpremise.id即可获得合法的资源ID,用法和引用当前配置内管理的IP组完全一致。

最佳实践提示

  • 禁止手动拼接Azure资源ID,不同环境的订阅ID、资源组名称、资源命名可能存在差异,直接引用资源或数据源导出的id属性可以完全避免格式错误、环境适配问题
  • 做IP组名称映射时,注意对齐自定义标识和实际资源的对应关系,避免出现索引不存在的报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 11:48:16