使用Terraform部署对接PostgreSQL的AWS Lambda 如何传递RDS主机名?
解决方案
1. 修正Terraform配置
1.1 修复Secrets Manager配置,写入动态生成的RDS信息
你之前用静态变量存储secrets内容的方式存在问题,RDS实例创建后会输出address、port等动态属性,直接引用这些属性写入Secrets Manager即可,不需要额外定义动态variable:
# 删掉原来的var.pgdb-secrets变量定义,直接在secret版本里引用动态值 resource "aws_secretsmanager_secret_version" "pgdb" { secret_id = aws_secretsmanager_secret.pgdb.id secret_string = jsonencode({ username = var.pgdb-username password = random_password.pgdb.result host = aws_db_instance.bl-db.address port = aws_db_instance.bl-db.port dbname = aws_db_instance.bl-db.name }) }
1.2 修复RDS资源的配置错误
你原来的RDS用户名引用写法有误,var.pgdb-username是普通字符串变量,没有.result属性:
resource "aws_db_instance" "bl-db" { # 其他原有配置保留不变 username = var.pgdb-username # 去掉末尾的.result password = random_password.pgdb.result # 该配置是正确的,random_password的输出属性为result # 其他原有配置保留不变 }
1.3 给Lambda角色添加Secrets Manager访问权限
当前的Lambda执行角色只有基础运行权限,没有读取Secrets的权限,需要挂载对应IAM策略:
resource "aws_iam_role_policy_attachment" "lambda_secrets_access" { role = aws_iam_role.lambda-iam.name policy_arn = "arn:aws:iam::aws:policy/SecretsManagerReadWrite" # 生产环境建议自定义策略,缩窄权限到仅允许访问该PG密钥,避免权限过大 }
1.4 (可选)通过Lambda环境变量传递非敏感配置
如果你不想把主机地址这类非敏感信息放到Secrets里,也可以直接通过Lambda的环境变量传递,代码中直接读取环境变量即可:
resource "aws_lambda_function" "lambda" { # 其他原有配置保留 environment { variables = { PG_HOST = aws_db_instance.bl-db.address PG_PORT = aws_db_instance.bl-db.port PG_DB_NAME = aws_db_instance.bl-db.name } } }
2. 修正Lambda Python代码
2.1 修复变量引用和逻辑问题
你原来的代码存在导入别名不一致、host_name未赋值、重复建表报错等问题,修正后代码如下:
#!env/bin/python import json import os import random import psycopg2 as pg import awswrangler.secretsmanager as awssm # 方案1:直接从Secrets读取所有配置 pg_secrets = awssm.get_secret_json("postgres-database") database_name = pg_secrets.get("dbname") table_name = "cities" username = pg_secrets.get("username") password = pg_secrets.get("password") port = pg_secrets.get("port") host_name = pg_secrets.get("host") # 方案2:如果使用了Lambda环境变量,可按以下方式读取 # database_name = os.environ.get("PG_DB_NAME") # port = os.environ.get("PG_PORT") # host_name = os.environ.get("PG_HOST") # username = awssm.get_secret_json("postgres-database").get("username") # password = awssm.get_secret_json("postgres-database").get("password") def lambda_handler(event, context): cxn = pg.connect( user=username, password=password, host=host_name, port=port, database=database_name ) # 新增表存在性判断,避免重复建表报错 with cxn.cursor() as csr: csr.execute("SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = 'cities')") if not csr.fetchone()[0]: query_create_table = "create table cities ( ix serial primary key, names varchar(50) unique not null );" csr.execute(query_create_table) query_insert_data = "insert into cities (names) values ('Washington'), ('Philadelphia'), ('New York'), ('Chicago'), ('Los Angeles'), ('Seattle'), ('Portland'), ('Dallas'), ('Miami'), ('Charlotte');" csr.execute(query_insert_data) cxn.commit() # 直接用SQL随机查询,写法更简洁 csr.execute("SELECT names FROM cities ORDER BY RANDOM() LIMIT 1;") random_record = csr.fetchone()[0] cxn.close() return {"statusCode" : 200, "body" : f"a random city is {random_record}" }
额外优化建议
- 生产环境不要开启RDS的公网访问,建议将Lambda和RDS都部署在同一个VPC的私有子网中,提升安全性
- 可以为Lambda添加数据库连接池组件,避免每次冷启动都新建连接消耗RDS资源
内容的提问来源于stack exchange,提问作者Frank Burdell
相关产品推荐
相关产品推荐

