如何强制CloudFormation解析Secrets Manager值并更新Lambda环境变量?
你猜的完全没错——CloudFormation确实是对比模板的原始声明内容,而不是解析后的实际值。你模板里的!Sub '{{resolve:secretsmanager:${Secret}:SecretString:KEY}}'是一个部署时才会解析的动态引用,只要这个表达式本身没变化,哪怕Secrets Manager里的密钥已经更新,CloudFormation也会判定“没有需要部署的变更”,自然不会触发Lambda的重新部署。
解决方案1:添加强制更新的触发字段(最推荐)
给Lambda函数加一个不会影响业务的自定义配置字段,每次需要更新时修改它的值,让CloudFormation认为Lambda的配置发生了变化,从而重新部署并解析最新的密钥。
方式A:硬编码临时版本号到模板
修改Lambda的环境变量,新增一个FORCE_DEPLOY字段,每次更新时修改它的值(比如从v1改成v2):
Resources: Function: Type: AWS::Serverless::Function Properties: Environment: Variables: SECRET_KEY: !Sub '{{resolve:secretsmanager:${Secret}:SecretString:KEY}}' FORCE_DEPLOY: 'v2' # 每次更新时修改这个值即可 Secret: Type: AWS::SecretsManager::Secret Properties: Name: 'very-secret-thing' SecretString: '{"KEY":"dummy"}'
方式B:用参数传递版本号(更灵活)
如果你不想每次改模板,可以把版本号做成CloudFormation参数,部署时通过命令行传递:
Parameters: ForceDeployVersion: Type: String Default: 'v1' Resources: Function: Type: AWS::Serverless::Function Properties: Environment: Variables: SECRET_KEY: !Sub '{{resolve:secretsmanager:${Secret}:SecretString:KEY}}' FORCE_DEPLOY: !Ref ForceDeployVersion Secret: Type: AWS::SecretsManager::Secret Properties: Name: 'very-secret-thing' SecretString: '{"KEY":"dummy"}'
部署时执行:
aws cloudformation deploy \ --stack-name your-stack-name \ --template-file your-template.yaml \ --parameter-overrides ForceDeployVersion=v2
解决方案2:修改Lambda的元数据字段
除了环境变量,你也可以修改Lambda的Description或者Tags字段,比如给Description加个时间戳:
Resources: Function: Type: AWS::Serverless::Function Properties: Description: "Lambda function using secret - updated 2024-05-20" # 每次更新时修改这里的时间 Environment: Variables: SECRET_KEY: !Sub '{{resolve:secretsmanager:${Secret}:SecretString:KEY}}' # 其他资源不变
只要这个字段的值发生变化,CloudFormation就会重新部署Lambda,同时解析最新的Secrets Manager值。
解决方案3:直接用CLI更新(不推荐,会脱离CloudFormation管理)
如果你只是临时需要更新,也可以绕过CloudFormation直接用AWS CLI更新Lambda的环境变量,但要注意:下次CloudFormation部署时,会把环境变量改回模板里的配置(也就是重新解析当时的密钥值),所以这个方法只适合临时场景:
# 获取最新的密钥值 SECRET_VALUE=$(aws secretsmanager get-secret-value --secret-id very-secret-thing --query SecretString --output text | jq -r .KEY) # 更新Lambda环境变量 aws lambda update-function-configuration --function-name your-function-name --environment "Variables={SECRET_KEY=$SECRET_VALUE}"
为什么会出现这个问题?
CloudFormation是声明式基础设施即代码工具,它的变更检测逻辑是对比你提交的模板和当前栈的模板(或已部署资源的配置快照)。resolve这类动态引用是在部署阶段才会被解析成实际值的,所以模板里的表达式没变的话,CloudFormation就会认为资源配置没有变化,不会触发任何更新。
内容的提问来源于stack exchange,提问作者Jørn Schou-Rode

