Terraform for_each 遍历YAML配置仅生效最后一条ingress规则的问题
问题根因排查
两个核心问题叠加导致仅最后一条ingress规则生效:
1. YAML结构存在语法逻辑错误
标准YAML解析器对同层级重复键的处理规则为「后值覆盖前值」,你当前YAML文件里在test-security-group节点下重复写了3次ingress_rules键,实际经过yamldecode解码后的结构里,ingress_rules根本不是包含3条规则的列表,只剩最后一条端口为8080的规则对象。
后续代码里each.value.ingress_rules[*]的splat操作符,会把这个单个对象转换成仅含1个元素的列表,直接导致dynamic块只循环一次,输出那一条被覆盖剩下的8080端口规则——这就是为什么计划输出里永远只有最后一条ingress,前两条规则在YAML解码阶段就已经被覆盖丢失了。
另外YAML里的is_self_source值带了引号,是字符串类型的"false",不是布尔值,直接赋值给self属性存在类型不匹配风险。
2. Terraform dynamic块的循环变量引用错误
你在dynamic块的content配置里,始终引用外层安全组资源循环的each.value变量,完全没有用到dynamic块自身遍历生成的循环迭代值。哪怕YAML结构修正为标准列表,这种写法也只会让所有dynamic生成的规则块复用同一份外层值,无法正确读取单条规则的配置。
修正方案
第一步:调整YAML结构为标准数组格式
把重复的键改成数组定义(每个规则用-标记为列表项),移除布尔值的多余引号:
test-security-group: ingress_rules: - description: "Test description" is_self_source: false from_port: 80 to_port: 80 protocol: "tcp" cidr_blocks: ["0.0.0.0/0"] - description: "Test description 2" is_self_source: false from_port: 443 to_port: 443 protocol: "tcp" cidr_blocks: ["0.0.0.0/0"] - description: "Test description 3" is_self_source: false from_port: 8080 to_port: 8080 protocol: "tcp" cidr_blocks: ["0.0.0.0/0"] egress_rules: - description: "Test description 4" is_self_source: false from_port: 80 to_port: 80 protocol: "tcp" cidr_blocks: ["0.0.0.0/0"]
第二步:修正dynamic块的变量引用逻辑
dynamic块的默认迭代器与块同名(ingress块的迭代器变量名为ingress,egress块为egress),单条规则的属性需要从迭代器变量上读取,而非外层安全组循环的each变量:
resource "aws_security_group" "security_group" { for_each = var.security_group_list name = each.key dynamic "ingress" { for_each = each.value.ingress_rules content { description = ingress.value.description from_port = ingress.value.from_port to_port = ingress.value.to_port protocol = ingress.value.protocol cidr_blocks = ingress.value.cidr_blocks self = ingress.value.is_self_source } } dynamic "egress" { for_each = each.value.egress_rules content { description = egress.value.description from_port = egress.value.from_port to_port = egress.value.to_port protocol = egress.value.protocol cidr_blocks = egress.value.cidr_blocks self = egress.value.is_self_source } } }
兼容优化建议
如果需要兼容用户在YAML里只写单条规则(不套数组)的场景,可以在dynamic的for_each里增加类型判断,自动把单条规则转成单元素列表,避免Terraform报错:
# 兼容非数组格式的单条ingress规则 dynamic "ingress" { for_each = can(each.value.ingress_rules[0]) ? each.value.ingress_rules : [each.value.ingress_rules] content { # 原有content配置保持不变 } }
内容的提问来源于stack exchange,提问作者sd-gallowaystorm
相关产品推荐
相关产品推荐

