You need to enable JavaScript to run this app. Terraform for_each 遍历YAML配置仅生效最后一条ingress规则的问题
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.31 17:36:05