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

Terraform安全组for_each循环问题:重复键致规则被忽略

问题根源

你遇到的问题是因为Map类型的键必须唯一——你定义的变量被Terraform自动推断为Map结构,重复的1111键会直接被后面的条目覆盖,导致第一条规则根本不会被处理,这是键值对结构的通用特性,并非Terraform的bug。

解决方案

要实现同一个端口对应多条安全组规则,需要调整变量结构避免重复键,同时确保每个规则都有唯一标识供for_each遍历。以下是两种可行方案:

方案1:Map嵌套List(保留端口分组)

把每个端口对应的多条规则封装为List,同时给变量指定明确的类型约束(避免用any导致的类型模糊):

variable "ingress_ports_cidr_blocks" {
  type = map(list(object({
    description = string
    protocol    = string
    cidr_blocks = list(string)
  })))
  default = {
    1111 = [
      {description = "test" , protocol = "TCP" , cidr_blocks = ["0.0.0.0/0"]},
      {description = "test" , protocol = "TCP" , cidr_blocks = ["10.10.10.0/24"]}
    ],
    2222 = [
      {description = "test" , protocol = "TCP" , cidr_blocks = ["0.0.0.0/0"]}
    ]
  }
}

然后在安全组资源中,通过flatten函数展开嵌套结构,生成每个规则的唯一标识:

resource "aws_security_group" "sg_ec2" {
  name        = "ec2-sg"
  vpc_id      = data.aws_vpc.env_vpc.id
  description = var.sgDescription

  dynamic "ingress" {
    for_each = flatten([
      for port, rules in var.ingress_ports_cidr_blocks : [
        for idx, rule in rules : {
          key  = "${port}-${idx}" # 用端口+索引作为唯一键,确保每个规则独立
          port = port
          rule = rule
        }
      ]
    ])
    content {
      description = ingress.value.rule.description
      from_port   = ingress.value.port
      to_port     = ingress.value.port
      protocol    = ingress.value.rule.protocol
      cidr_blocks = ingress.value.rule.cidr_blocks
    }
  }
}

方案2:直接用List(更直观)

如果不需要按端口分组,直接把所有规则定义为List,每个元素包含端口和规则信息:

variable "ingress_rules" {
  type = list(object({
    port        = number
    description = string
    protocol    = string
    cidr_blocks = list(string)
  }))
  default = [
    {port = 1111, description = "test", protocol = "TCP", cidr_blocks = ["0.0.0.0/0"]},
    {port = 1111, description = "test", protocol = "TCP", cidr_blocks = ["10.10.10.0/24"]},
    {port = 2222, description = "test", protocol = "TCP", cidr_blocks = ["0.0.0.0/0"]}
  ]
}

对应的安全组资源配置:

resource "aws_security_group" "sg_ec2" {
  name        = "ec2-sg"
  vpc_id      = data.aws_vpc.env_vpc.id
  description = var.sgDescription

  dynamic "ingress" {
    # 用索引作为唯一键,确保每个规则被独立处理
    for_each = { for idx, rule in var.ingress_rules : idx => rule }
    content {
      description = ingress.value.description
      from_port   = ingress.value.port
      to_port     = ingress.value.port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }
}
关键提示
  • 避免使用type = any:明确的类型约束能帮你提前发现结构错误,也让代码更易维护。
  • for_each依赖唯一键:所有被for_each遍历的集合必须包含唯一元素,否则Terraform会报错或忽略重复项。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 02:36:19