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

Terraform跨安全组互通规则变更后消失的原因与修复方案

问题:Terraform管理AWS安全组跨组规则时规则频繁消失

我通过Terraform创建了两个AWS安全组(分别用于EC2和RDS实例),并单独定义了两条允许它们之间互访的 ingress 规则。首次terraform apply后规则正常生效,但每次执行变更操作(哪怕修改的是其他无关资源),这两条跨组规则都会自动消失。必须先注释规则代码并apply(此时Terraform会提示删除规则,但实际AWS控制台中已经看不到这些规则了),再取消注释重新apply才能恢复,这种操作在生产环境中风险极高。

现有代码

安全组定义

resource "aws_security_group" "ec2_sg" {
  name        = "${var.project_name}-${var.environment}-ec2-sg"
  vpc_id      = var.vpc_id
  description = "Security Group for EC2 instance"

  ingress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["172.15.0.0/16", "172.18.0.0/16", "172.19.0.0/16"]
  }

  tags = {
    Name         = "${var.project_name}-${var.environment}-ec2-sg"
    Environment  = var.environment
    Project      = var.project_name
    ResourceType = "security-group"
  }
}

resource "aws_security_group" "rds_sg" {
  name        = "${var.project_name}-${var.environment}-rds-sg"
  vpc_id      = var.vpc_id
  description = "Security Group for RDS"

  ingress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["172.15.0.0/16", "172.18.0.0/16", "172.19.0.0/16"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name         = "${var.project_name}-${var.environment}-rds-sg"
    Environment  = var.environment
    Project      = var.project_name
    ResourceType = "security-group"
  }
}

独立的跨组规则定义

resource "aws_security_group_rule" "ec2_rule" {
  depends_on               = [aws_security_group.ec2_sg, aws_security_group.rds_sg]
  type                     = "ingress"
  from_port                = 0
  to_port                  = 0
  protocol                 = "-1"
  source_security_group_id = aws_security_group.rds_sg.id
  security_group_id        = aws_security_group.ec2_sg.id
}

resource "aws_security_group_rule" "rds_rule" {
  depends_on               = [aws_security_group.ec2_sg, aws_security_group.rds_sg]
  type                     = "ingress"
  from_port                = 0
  to_port                  = 0
  protocol                 = "-1"
  source_security_group_id = aws_security_group.ec2_sg.id
  security_group_id        = aws_security_group.rds_sg.id
}

原因分析

  1. Terraform状态计算逻辑冲突:AWS安全组规则本质是安全组的附属资源,当你在aws_security_group资源块外单独定义aws_security_group_rule时,Terraform会将这些规则视为独立资源。但如果后续对安全组本身做任何变更(哪怕是修改标签这类无关操作),Terraform会重新计算安全组的期望状态,此时它只会对比安全组资源块内定义的规则,外部的独立规则会被判定为“不属于该安全组的期望状态”,从而被标记为需要删除。
  2. 多余的depends_on干扰:代码中添加的depends_on完全没必要,因为aws_security_group_rule已经引用了安全组的ID,Terraform会自动处理依赖关系,多余的依赖声明可能引发状态计算的异常。

解决方案

方案1:将规则内嵌到安全组资源块中(推荐)

直接在aws_security_group内部定义跨组访问规则,让Terraform把安全组和规则视为一个整体管理,彻底避免状态不一致问题。

修改后的EC2安全组代码:

resource "aws_security_group" "ec2_sg" {
  name        = "${var.project_name}-${var.environment}-ec2-sg"
  vpc_id      = var.vpc_id
  description = "Security Group for EC2 instance"

  ingress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["172.15.0.0/16", "172.18.0.0/16", "172.19.0.0/16"]
  }

  # 允许RDS安全组访问EC2的规则
  ingress {
    from_port                = 0
    to_port                  = 0
    protocol                 = "-1"
    source_security_group_id = aws_security_group.rds_sg.id
  }

  tags = {
    Name         = "${var.project_name}-${var.environment}-ec2-sg"
    Environment  = var.environment
    Project      = var.project_name
    ResourceType = "security-group"
  }
}

修改后的RDS安全组代码:

resource "aws_security_group" "rds_sg" {
  name        = "${var.project_name}-${var.environment}-rds-sg"
  vpc_id      = var.vpc_id
  description = "Security Group for RDS"

  ingress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["172.15.0.0/16", "172.18.0.0/16", "172.19.0.0/16"]
  }

  # 允许EC2安全组访问RDS的规则
  ingress {
    from_port                = 0
    to_port                  = 0
    protocol                 = "-1"
    source_security_group_id = aws_security_group.ec2_sg.id
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name         = "${var.project_name}-${var.environment}-rds-sg"
    Environment  = var.environment
    Project      = var.project_name
    ResourceType = "security-group"
  }
}

之后删除原来的aws_security_group_rule资源块,执行terraform plan确认变更符合预期,再terraform apply即可。

方案2:保留独立规则(不推荐)

如果因特殊需求必须使用独立的aws_security_group_rule,需满足以下条件:

  • 安全组资源块内不能定义任何ingress/egress规则(AWS默认的全通出规则除外)
  • 后续永远不修改安全组的任何属性(包括标签、描述等)

这种方式依然存在状态漂移的风险,仅适合临时场景,不建议生产环境使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 17:44:54