如何通过AWS CloudFormation自定义资源动态生成Lambda应用配置文件
结论
完全可以通过CloudFormation自定义资源实现该需求,不需要进行本地文件写入操作,通过云上托管的配置存储结合资源依赖即可实现配置预生成后再部署Lambda的流程。
实现核心逻辑
- 首先通过一个辅助Lambda支撑自定义资源的执行逻辑,在自定义资源的Create/Update生命周期中完成动态配置生成,将生成的配置存入SSM参数存储、Secrets Manager或S3对象存储,自定义资源执行成功后才会进入后续资源创建流程
- 给目标Lambda资源添加
DependsOn属性,指定依赖上述自定义资源,强制CloudFormation在配置生成完成后才启动Lambda的创建流程 - 目标Lambda可以在启动时直接拉取预先生成的配置,也可以在部署阶段将配置作为环境变量注入,或者把配置文件打包进Lambda的部署包中使用
CloudFormation模板示例
以下是完整的YAML模板示例,实现动态生成配置后再创建目标Lambda的流程:
AWSTemplateFormatVersion: '2010-09-09' Parameters: DatabaseHost: Type: String AppApiKey: Type: String NoEcho: true Environment: Type: String Default: prod Resources: # 自定义资源执行角色,授予配置写入和日志上报权限 CustomResourceRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: CustomResourcePolicy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ssm:PutParameter - ssm:DeleteParameter - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: "*" # 生成配置的辅助Lambda ConfigGeneratorLambda: Type: AWS::Lambda::Function Properties: Runtime: python3.9 Role: !GetAtt CustomResourceRole.Arn Handler: index.lambda_handler Code: ZipFile: | import json import boto3 import cfnresponse ssm = boto3.client('ssm') def lambda_handler(event, context): response_data = {} try: if event['RequestType'] in ['Create', 'Update']: # 此处可编写自定义的动态配置生成逻辑,支持拼接其他资源的输出参数 app_config = { "db_host": event['ResourceProperties']['DbHost'], "api_key": event['ResourceProperties']['ApiKey'], "env": event['ResourceProperties']['Env'], "enable_feature": True } # 配置写入SSM参数存储,敏感配置可使用SecureString类型加密存储 ssm.put_parameter( Name="/app/lambda/runtime_config", Value=json.dumps(app_config), Type="SecureString", Overwrite=True ) response_data['ConfigParameterName'] = "/app/lambda/runtime_config" elif event['RequestType'] == 'Delete': # 栈删除时自动清理生成的配置 ssm.delete_parameter(Name="/app/lambda/runtime_config") cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data) except Exception as e: cfnresponse.send(event, context, cfnresponse.FAILED, {"Error": str(e)}) # 自定义资源,触发配置生成流程 GenerateAppConfig: Type: Custom::GenerateAppConfig Properties: ServiceToken: !GetAtt ConfigGeneratorLambda.Arn DbHost: !Ref DatabaseHost ApiKey: !Ref AppApiKey Env: !Ref Environment # 目标业务Lambda角色,授予配置读取权限 TargetLambdaRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: LambdaConfigReadPolicy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - ssm:GetParameter - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: "*" # 目标业务Lambda,依赖配置生成完成后才会创建 TargetLambda: Type: AWS::Lambda::Function DependsOn: GenerateAppConfig Properties: Runtime: python3.9 Role: !GetAtt TargetLambdaRole.Arn Handler: index.lambda_handler Environment: Variables: CONFIG_PARAM_NAME: !GetAtt GenerateAppConfig.ConfigParameterName Code: ZipFile: | import json import boto3 ssm = boto3.client('ssm') # Lambda冷启动时拉取预先生成的配置 runtime_config = json.loads(ssm.get_parameter( Name="/app/lambda/runtime_config", WithDecryption=True )['Parameter']['Value']) def lambda_handler(event, context): # 业务逻辑直接使用预生成的配置即可 return { 'statusCode': 200, 'body': json.dumps({'config_loaded': True, 'env': runtime_config['env']}) }
注意事项
- 示例中的
Resource: "*"仅作演示使用,生产环境请按最小权限原则限制到具体的SSM参数ARN、日志组ARN等资源 - 如果你需要将配置作为独立文件嵌入Lambda部署包,可以在自定义资源中生成配置后上传到S3存储桶,将S3对象地址和版本作为自定义资源的输出,目标Lambda的
Code属性直接引用该S3地址即可 - 敏感配置建议使用SSM SecureString或Secrets Manager存储,不要直接明文写入Lambda环境变量
内容的提问来源于stack exchange,提问作者Hakuna Matata
相关产品推荐
相关产品推荐

