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

Terraform部署AWS时子网与安全组销毁卡顿问题求助

问题描述

1. 资源销毁卡顿

从自定义VPC(CIDR 10.0.0.0/16)切换到默认VPC后,执行terraform apply时,aws_subnet.main和aws_security_group.lambda_security_group一直卡在「Still destroying...」循环,无法完成资源销毁或更新。

2. 网络配置需求

需要实现两个核心访问能力:

  • Lambda函数对RDS Postgres实例的读写访问
  • 本地通过pgAdmin连接RDS实例

当前使用的Terraform配置片段如下:

基础VPC与子网配置

provider "aws" {
    region     = var.aws_region
    access_key = var.aws_access_key
    secret_key = var.aws_secret_key
}
    
data "aws_vpc" "default" {
    default = true
}

resource "aws_db_subnet_group" "rds_subnet_group" {
    name       = "scrapr-rds-subnet-group"
    subnet_ids = [aws_subnet.main.id, aws_subnet.secondary.id]
}

resource "aws_subnet" "main" {
    vpc_id            = data.aws_vpc.default.id
    cidr_block        = "10.0.1.0/24"
    availability_zone = "eu-central-1a"
}

resource "aws_subnet" "secondary" {
    vpc_id            = data.aws_vpc.default.id
    cidr_block        = "10.0.2.0/24"
    availability_zone = "eu-central-1b"
}

安全组配置

resource "aws_security_group" "rds_security_group" {
    name        = "scrapr_rds_security_group"
    description = "Security group for Scrapr RDS instance"
    vpc_id      = data.aws_vpc.default.id

    ingress {
        from_port   = 5432
        to_port     = 5432
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }
    ingress {
        from_port = 5432
        to_port   = 5432
        protocol  = "tcp"
    }

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

resource "aws_security_group" "lambda_security_group" {
    name        = "scrapr_lambda_security_group"
    description = "Security group for Scrapr Lambda function"
    vpc_id      = data.aws_vpc.default.id

    # Allow outbound connections to the RDS instance
    egress {
        from_port = 0
        to_port   = 0
        protocol  = "-1"
    }
}

RDS与Lambda配置

resource "aws_db_instance" "scrapr_rds_instance" {
    identifier             = "scrapr-rds-instance"
    engine                 = "postgres"
    engine_version         = "14.7"
    instance_class         = "db.t3.micro"
    allocated_storage      = 20
    storage_type           = "gp2"
    username               = var.db_username
    password               = var.db_password
    db_subnet_group_name   = aws_db_subnet_group.rds_subnet_group.name
    vpc_security_group_ids = [aws_security_group.rds_security_group.id]
    publicly_accessible    = false
}

resource "aws_lambda_function" "processing_lambda" {
    function_name = "processing_lambda"
    ...
    vpc_config {
        subnet_ids         = [aws_subnet.main.id]
        security_group_ids = [aws_security_group.lambda_security_group.id]
    }
}

卡顿环节日志

>aws_security_group.lambda_security_group: Still destroying... [4m0s elapsed]
>aws_security_group.lambda_security_group: Still destroying... [4m10s elapsed]
>aws_subnet.main: Still destroying... [4m10s elapsed]
>aws_subnet.main: Still destroying... [4m20s elapsed]
>aws_security_group.lambda_security_group: Still destroying... [4m20s elapsed]
>aws_security_group.lambda_security_group: Still destroying... [4m30s elapsed]
>aws_subnet.main: Still destroying... [4m30s elapsed]
>aws_security_group.lambda_security_group: Still destroying... [4m40s elapsed]
>aws_subnet.main: Still destroying... [4m40s elapsed]
>aws_security_group.lambda_security_group: Still destroying... [4m50s elapsed]
>aws_subnet.main: Still destroying... [4m50s elapsed]

解决方案

一、先解决资源销毁卡顿问题

卡顿的核心原因是资源被占用无法释放,按以下步骤修复:

  1. 解除Lambda对目标资源的占用
    临时修改Lambda的Terraform配置,注释掉vpc_config块,执行terraform apply让Lambda退出VPC,不再占用子网和安全组。
  2. 单独销毁卡顿资源
    执行命令:
    terraform destroy -target aws_subnet.main -target aws_security_group.lambda_security_group
    
  3. 避免后续重复问题
    不要在默认VPC中创建自定义子网,直接用默认VPC自带的默认子网,减少资源依赖复杂度;如果必须自定义子网,确保Terraform依赖关系清晰,必要时用depends_on显式声明。

二、配置Lambda访问RDS + 本地pgAdmin连接

核心配置逻辑

  • RDS安全组:只允许Lambda安全组的5432端口流量(PostgreSQL),以及你的本地公网IP流量(用于pgAdmin)。
  • Lambda安全组:允许出站到RDS的5432端口,同时允许出站到S3(因为Lambda要读写S3)。
  • RDS需开启publicly_accessible = true,才能让本地pgAdmin通过公网连接。

修正后的完整Terraform配置

1. 基础VPC与子网(使用默认VPC的默认子网)

provider "aws" {
    region     = var.aws_region
    access_key = var.aws_access_key
    secret_key = var.aws_secret_key
}

data "aws_vpc" "default" {
    default = true
}

# 获取默认VPC的所有默认子网
data "aws_subnets" "default" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.default.id]
  }

  filter {
    name   = "default-for-az"
    values = ["true"]
  }
}

resource "aws_db_subnet_group" "rds_subnet_group" {
    name       = "scrapr-rds-subnet-group"
    subnet_ids = data.aws_subnets.default.ids
}

2. 安全组配置

resource "aws_security_group" "rds_security_group" {
    name        = "scrapr_rds_security_group"
    description = "Security group for Scrapr RDS instance"
    vpc_id      = data.aws_vpc.default.id

    # 允许Lambda安全组访问PostgreSQL端口
    ingress {
        from_port       = 5432
        to_port         = 5432
        protocol        = "tcp"
        security_groups = [aws_security_group.lambda_security_group.id]
    }

    # 允许本地公网IP访问(替换成你的本地公网IP,比如114.xxx.xxx.xxx/32,生产环境不要用0.0.0.0/0)
    ingress {
        from_port   = 5432
        to_port     = 5432
        protocol    = "tcp"
        cidr_blocks = ["你的本地公网IP/32"]
    }

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

resource "aws_security_group" "lambda_security_group" {
    name        = "scrapr_lambda_security_group"
    description = "Security group for Scrapr Lambda function"
    vpc_id      = data.aws_vpc.default.id

    # 允许出站到RDS的PostgreSQL端口
    egress {
        from_port       = 5432
        to_port         = 5432
        protocol        = "tcp"
        security_groups = [aws_security_group.rds_security_group.id]
    }

    # 允许出站到S3(Lambda读写S3必须)
    egress {
        from_port   = 0
        to_port     = 0
        protocol    = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

3. RDS、Lambda与IAM权限配置

resource "aws_db_instance" "scrapr_rds_instance" {
    identifier             = "scrapr-rds-instance"
    engine                 = "postgres"
    engine_version         = "14.7"
    instance_class         = "db.t3.micro"
    allocated_storage      = 20
    storage_type           = "gp2"
    username               = var.db_username
    password               = var.db_password
    db_subnet_group_name   = aws_db_subnet_group.rds_subnet_group.name
    vpc_security_group_ids = [aws_security_group.rds_security_group.id]
    # 开启公网访问,允许本地pgAdmin连接
    publicly_accessible    = true
    backup_retention_period = 7 # 可选:启用自动备份
}

resource "aws_lambda_function" "processing_lambda" {
    function_name = "processing_lambda"
    # 填充你的Lambda代码、运行时等配置
    ...
    vpc_config {
        subnet_ids         = data.aws_subnets.default.ids
        security_group_ids = [aws_security_group.lambda_security_group.id]
    }
    role = aws_iam_role.lambda_exec_role.id
}

# Lambda所需的IAM角色(必须配置,否则无法访问VPC、RDS、S3)
resource "aws_iam_role" "lambda_exec_role" {
  name = "lambda-exec-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      }
    ]
  })
}

# 附加Lambda基础执行权限
resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
  role       = aws_iam_role.lambda_exec_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

# 附加Lambda VPC访问权限
resource "aws_iam_role_policy_attachment" "lambda_vpc_access" {
  role       = aws_iam_role.lambda_exec_role.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
}

# 自定义权限:允许Lambda读写S3和连接RDS
resource "aws_iam_role_policy" "lambda_s3_rds_access" {
  name = "lambda-s3-rds-access"
  role = aws_iam_role.lambda_exec_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = ["s3:GetObject", "s3:PutObject"]
        Resource = "arn:aws:s3:::你的S3桶名称/*"
      },
      {
        Effect = "Allow"
        Action = ["rds-db:connect"]
        Resource = "arn:aws:rds-db:${var.aws_region}:${data.aws_caller_identity.current.account_id}:dbuser:${aws_db_instance.scrapr_rds_instance.resource_id}/${var.db_username}"
      }
    ]
  })
}

data "aws_caller_identity" "current" {}

三、验证步骤

  1. 执行terraform apply后,在AWS控制台查看RDS实例的端点和端口。
  2. 打开pgAdmin,新建服务器,输入RDS端点、端口、用户名密码,验证是否能成功连接。
  3. 上传测试CSV到触发S3桶,查看Lambda的CloudWatch日志,确认是否能完成数据清洗并写入RDS。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 23:47:02