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

如何在Terraform中遍历嵌套对象映射创建防火墙规则?

解决Terraform中azurerm_postgresql_flexible_server_firewall_rule读取嵌套对象映射的问题

需求背景

需要让azurerm_postgresql_flexible_server_firewall_rule资源读取给定的嵌套对象结构的变量/本地值,同时满足约束条件:通过客户名称关联对应PostgreSQL服务器,且不能修改原变量结构。

现有资源代码

resource "azurerm_postgresql_flexible_server_firewall_rule" "pgsql_fw_rules" {
  for_each = ???
  server_id        = module.pgsql[each.key].id
  name             = ???
  start_ip_address = ???
  end_ip_address   = ???
}

变量/本地值结构

output1 = {
  aa1 = {
    azure_services = {
      end_ip   = "0.0.0.0"
      start_ip = "0.0.0.0"
    }
    rule2          = {
      end_ip   = "10.255.255.255"
      start_ip = "10.0.0.1"
    }
    ruleabc        = {
      end_ip   = "1.1.1.2"
      start_ip = "1.1.1.1"
    }
    tf_user        = {
      end_ip   = "127.0.0.2"
      start_ip = "127.0.0.1"
    }
  }
  aa2 = {
    azure_services = {
      end_ip   = "0.0.0.0"
      start_ip = "0.0.0.0"
    }
    rulexyz        = {
      end_ip   = "1.1.1.2"
      start_ip = "1.1.1.1"
    }
    tf_user        = {
      end_ip   = "127.0.0.2"
      start_ip = "127.0.0.1"
    }
  }
}

约束条件

  • 资源需通过客户名称(aa1、aa2)关联对应的PostgreSQL服务器module.pgsql[客户名].id
  • 禁止修改原变量/本地值output1
  • 优先在resource的for_each中处理,或创建新本地值

解决方案

方案1:创建新本地值(推荐,可读性更高)

先将嵌套的output1扁平化为适合for_each的结构,每个元素对应一条防火墙规则,包含客户名称、规则名称、IP信息:

locals {
  flattened_fw_rules = merge([
    for customer_key, customer_rules in var.output1 : {
      for rule_name, rule_details in customer_rules :
      "${customer_key}/${rule_name}" => {
        customer_key = customer_key
        rule_name    = rule_name
        start_ip     = rule_details.start_ip
        end_ip       = rule_details.end_ip
      }
    }
  ]...)
}

然后在资源中使用这个本地值:

resource "azurerm_postgresql_flexible_server_firewall_rule" "pgsql_fw_rules" {
  # each.key 为复合键(如"aa1/azure_services"),保证每个规则实例唯一
  for_each = local.flattened_fw_rules

  server_id        = module.pgsql[each.value.customer_key].id
  name             = each.value.rule_name
  start_ip_address = each.value.start_ip
  end_ip_address   = each.value.end_ip
}

方案2:直接在for_each中编写嵌套表达式

如果不想创建额外本地值,可以直接在for_each中用嵌套for和flatten实现:

resource "azurerm_postgresql_flexible_server_firewall_rule" "pgsql_fw_rules" {
  for_each = {
    for rule in flatten([
      for customer_key, customer_rules in var.output1 : [
        for rule_name, rule_details in customer_rules : {
          id           = "${customer_key}/${rule_name}"
          customer_key = customer_key
          rule_name    = rule_name
          start_ip     = rule_details.start_ip
          end_ip       = rule_details.end_ip
        }
      ]
    ]) : rule.id => rule
  }

  server_id        = module.pgsql[each.value.customer_key].id
  name             = each.value.rule_name
  start_ip_address = each.value.start_ip
  end_ip_address   = each.value.end_ip
}

关键说明

  • 由于每个客户对应多条防火墙规则,for_each的key必须是唯一的复合键(如客户名/规则名),否则会出现资源实例冲突
  • 通过each.value.customer_key可以获取到客户名称(aa1、aa2),从而关联对应的PostgreSQL服务器ID
  • 两种方案都无需修改原output1结构,完全符合约束要求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 15:43:15