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

Terraform:将负载均衡器IP添加至EC2实例安全组的问题

解决方案:Terraform动态配置安全组允许ALB访问EC2(解决循环依赖)

你的核心问题是共用安全组导致的循环依赖,以及无法动态获取ALB IP添加安全组规则。以下是两种可行方案,推荐用第一种彻底解决问题:


方案1:拆分安全组(推荐,彻底避免循环依赖)

将ALB和EC2的安全组分开,EC2安全组通过安全组ID引用允许ALB的流量,无需依赖ALB的具体IP,同时消除循环依赖。

实现步骤

  1. 先创建ALB专用安全组:仅允许你的公网IP访问ALB的业务端口(如80/443)。
  2. 创建EC2专用安全组:允许ALB安全组访问EC2的应用端口,同时保留你的IP直接访问EC2的规则。
  3. EC2模块使用EC2安全组,ALB模块使用ALB安全组。

Terraform代码示例

# 1. 创建ALB专用安全组
resource "aws_security_group" "alb_sg" {
  name        = "alb-security-group"
  description = "Allow inbound from my IP to ALB"
  vpc_id      = var.vpc_id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = [var.my_public_ip] # 你的公网IP,格式为x.x.x.x/32
  }

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

# 2. 创建EC2专用安全组
resource "aws_security_group" "ec2_sg" {
  name        = "ec2-security-group"
  description = "Allow inbound from ALB and my IP"
  vpc_id      = var.vpc_id

  # 允许ALB安全组访问EC2应用端口(核心规则)
  ingress {
    from_port       = 80
    to_port         = 80
    protocol        = "tcp"
    security_groups = [aws_security_group.alb_sg.id]
  }

  # 保留你的IP直接访问EC2(用于测试)
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = [var.my_public_ip]
  }

  # 可选:允许SSH访问EC2
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = [var.my_public_ip]
  }

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

# 3. 调用EC2模块,使用EC2专用安全组
module "ec2_instances" {
  source = "./modules/ec2"

  instance_count     = 2
  vpc_id             = var.vpc_id
  subnet_ids         = var.public_subnet_ids
  security_group_ids = [aws_security_group.ec2_sg.id]
  # 其他EC2配置参数(如AMI、实例类型等)
}

# 4. 创建ALB及关联资源,使用ALB专用安全组
resource "aws_lb" "application_alb" {
  name               = "my-app-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb_sg.id]
  subnets            = var.public_subnet_ids
}

resource "aws_lb_target_group" "ec2_targets" {
  name     = "ec2-target-group"
  port     = 80
  protocol = "HTTP"
  vpc_id   = var.vpc_id

  health_check {
    path                = "/"
    protocol            = "HTTP"
    matcher             = "200"
    interval            = 30
    timeout             = 5
    healthy_threshold   = 2
    unhealthy_threshold = 2
  }
}

resource "aws_lb_target_group_attachment" "ec2_attach" {
  count = length(module.ec2_instances.instance_ids)

  target_group_arn = aws_lb_target_group.ec2_targets.arn
  target_id        = module.ec2_instances.instance_ids[count.index]
  port             = 80
}

resource "aws_lb_listener" "alb_http_listener" {
  load_balancer_arn = aws_lb.application_alb.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.ec2_targets.arn
  }
}

方案2:共用安全组(不推荐,仅作备选)

如果坚持共用一个安全组,可通过单独的aws_security_group_rule资源动态添加允许ALB流量的规则,但这种方式存在IP变更失效的风险(ALB缩放或重启可能更换IP)。

Terraform代码示例

# 共用安全组
resource "aws_security_group" "shared_sg" {
  name        = "shared-security-group"
  description = "Allow my IP and ALB traffic"
  vpc_id      = var.vpc_id

  # 允许你的IP访问
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = [var.my_public_ip]
  }

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

# 创建ALB
resource "aws_lb" "application_alb" {
  name               = "my-app-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.shared_sg.id]
  subnets            = var.public_subnet_ids
}

# 动态添加允许ALB IP的安全组规则
resource "aws_security_group_rule" "alb_access" {
  type              = "ingress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  security_group_id = aws_security_group.shared_sg.id
  cidr_blocks       = [cidrhost(aws_lb.application_alb.private_ip, 32)]
  depends_on        = [aws_lb.application_alb]
}

关键说明

  • 方案1是AWS官方推荐的方式:通过安全组ID引用,无需关注ALB的具体IP,自动适配ALB的IP变更,同时彻底消除循环依赖。
  • 方案2仅适合临时场景,因为ALB可能有多个ENI IP,且IP会随资源变更而变化,存在访问失效的风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 19:16:07