使用IAM认证连接Lambda与Aurora MySQL数据库(已解决)
已解决:通过RDS代理实现Lambda使用IAM认证连接Aurora MySQL
简要说明(TLDR)
我的Aurora MySQL数据库、RDS代理、EC2实例和Lambda函数均处于同一VPC内,各资源安全组已配置必要的入站/出站规则;Lambda配置了包含PyMySQL和rds-combined-ca-bundle(也尝试过global-bundle)的层,且关联了权限正确的IAM角色;但发现即使在同一VPC中,Lambda>配置>RDS数据库选项无法选择目标数据库。
测试情况
关闭代理的IAM强制认证,将MySQL用户改为mysql_native_password时,Lambda可成功连接该用户;且只有当代理关联的Secrets Manager密钥中的用户名与登录用户名匹配时才能连接——即不使用IAM认证时连接正常,但开启IAM强制认证、将数据库用户改为AWSAuthenticationPlugin并使用IAM令牌作为密码时,无论如何操作都无法连接。
详细配置说明
Aurora MySQL数据库详情
- 引擎版本:8.0.mysql_aurora.3.09.0(开发/测试环境)
- 配置:Serverless V2、标准集群存储、可公开访问,启用IAM认证;所有资源共用同一新建VPC
- 安全组:允许自身、Lambda、EC2和RDS代理的IP/安全组访问的入站规则
- 端点:拥有读写两个端点
EC2实例详情
- 配置:Amazon Linux 2023 AMI、t2.micro实例类型,新建密钥对,与数据库同VPC
- 安全组:允许自身入站、全量出站
- 操作:通过PowerShell SSH登录后,用管理员用户连接数据库,创建并配置IAM认证用户:
ALTER USER 'user'@'%' IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS';
并为该用户分配数据库访问权限。
RDS代理详情
- 创建MariaDB和MySQL代理,目标组指向目标数据库
- 关联IAM角色:拥有
SecretsManagerReadWrite权限 - 关联Secrets Manager密钥:包含
dbInstanceIdentifier、engine、host(集群端点)、port、resourceId(集群)、username(IAM数据库用户名)、password(该用户转为IAM认证前的旧密码) - 认证配置:认证类型为MySQL Native Password,启用IAM强制认证,连接要求传输层安全,与数据库同VPC
Lambda详情
- 基础配置:Python 3.13运行时、x86_64架构,与数据库同VPC且选择相同的3个子网
- IAM角色:包含
AWSLambdaVPCAccessExecutionRole策略及以下内联策略:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "rds-db:connect" ], "Resource": [ "arn:aws:rds-db:{MyRegion}:{MyAccountNumber}:dbuser:{Proxy Id}/{DBUser}" ] } ] }
- 安全组:配置全量出站及指向RDS代理的出站规则
- 环境变量:
rds_db_name: DatabaseName rds_password: password rds_port: 3306 rds_proxy_host: Proxy Endpoint rds_region: us-east-2 rds_username: Name Of DB User
- 注意:即使在同一VPC中,Lambda配置页的RDS数据库选项无法选择目标数据库
初始Lambda代码
import pymysql import sys import boto3 import os # rds settings username = os.environ['rds_username'] proxy_host = os.environ['rds_proxy_host'] db_name = os.environ['rds_db_name'] region = os.environ['AWS_REGION'] port = 3306 os.environ['LIBMYSQL_ENABLE_CLEARTEXT_PLUGIN'] = '1' def lambda_handler(event, context): client = boto3.client('rds') token = client.generate_db_auth_token( DBHostname=proxy_host, Port=port, DBUsername=username, Region=region ) try: # Connect using IAM token connection = pymysql.connect( host=proxy_host, user=username, password=token, port=port, database=db_name, ssl_ca='/opt/python/global-bundle.pem' ) except Exception as e: print("Database connection failed due to {}".format(e))
问题解决说明
现已解决该问题,原因在于初始代码过度复杂化,删除冗余日志和多余导入、简化代码后即可正常连接,具体触发问题的细节尚不明确,但核心是实现逻辑被不必要的代码干扰。
内容的提问来源于stack exchange,提问作者JasperS
相关产品推荐
相关产品推荐

