如何在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
相关产品推荐
相关产品推荐

