我可以强制 CloudFormation 解析来自 Secrets Manager 的值吗?
Can I force CloudFormation to resolve values from Secrets Manager?
在下面(缩写为 CloudFormation 模板)中,我尝试配置 AWS Lambda 函数以从注入其环境的 AWS Secrets Manager 中获取值:
Resources:
Function:
Type: AWS::Serverless::Function
Properties:
Environment:
Variables:
SECRET_KEY: !Sub '{{resolve:secretsmanager:${Secret}:SecretString:KEY}}'
Secret:
Type: AWS::SecretsManager::Secret
Properties:
Name: 'very-secret-thing'
SecretString: '{"KEY":"dummy"}'
使用此模板创建堆栈时,一切都按预期进行。然后我去更改 CloudFormation 之外的秘密值,因为我真的不希望将秘密签入源代码管理。这是完全可能的,并且 documentation 暗示,只要我避免更改模板中 SecretString
的虚拟值,秘密的值就不会在后续的 CloudFormation 堆栈更新中被触及。
因此,在 AWS 控制台中设置实际机密后,我需要触发 Lambda 函数的重新部署,以便 CloudFormation 解析新的机密值并在函数的环境中设置。我该怎么做?
执行 aws cloudformation deploy
失败并显示消息:没有要部署的更改。
我怀疑 CloudFormation 正在将模板的 "raw" 版本与最后部署的版本进行比较,而没有首先解析对 Secrets Manager 的引用。是这样吗?是否有一些技巧可以强制提前取消引用?
脚注:我很清楚以这种方式使用 Secrets Manager 会导致密钥值在 AWS Lambda 控制台中可见,并且从 Secrets Manager 获取值运行时将是更安全的方法。这恰好超出了我希望做的范围。
您说读取 Lambda 中的值超出范围,但这确实是正确的解决方案。它不仅提高了安全性,而且允许 Lambda 在密钥轮换时获取最新值。
如果您在处理程序外部读取机密(也就是说,在初始化期间),则读取次数会最小化。如果这是连接到数据库的 java lambda,您还可以使用 secrets manager jdbc wrapper 来自动获取密钥。
您可以在 AWS::Serverless::Function
资源上人为地更改 其他内容 以强制它在您进行部署时进行更新。
例如,时间戳:
Parameters:
DeployTimestamp: { Type: String }
Resources:
Function:
Type: AWS::Serverless::Function
Properties:
Environment:
Variables:
SECRET_KEY: !Sub '{{resolve:secretsmanager:${Secret}:SecretString:KEY}}'
SECRET_KEY_UPDATED: !Ref DeployTimestamp
假设您从脚本进行部署,那么您每次都会执行 aws cloudformation deploy --parameter-overrides "DeployTimestamp=$(date)"
之类的操作来更改值。
当然,这样做的缺点是该函数将更新每个部署,即使机密尚未更新。如果这让你感到困扰,你可以变得更有趣,并将 aws secretsmanager describe-secret --query LastChangedDate
作为参数而不是当前时间注入。
在下面(缩写为 CloudFormation 模板)中,我尝试配置 AWS Lambda 函数以从注入其环境的 AWS Secrets Manager 中获取值:
Resources:
Function:
Type: AWS::Serverless::Function
Properties:
Environment:
Variables:
SECRET_KEY: !Sub '{{resolve:secretsmanager:${Secret}:SecretString:KEY}}'
Secret:
Type: AWS::SecretsManager::Secret
Properties:
Name: 'very-secret-thing'
SecretString: '{"KEY":"dummy"}'
使用此模板创建堆栈时,一切都按预期进行。然后我去更改 CloudFormation 之外的秘密值,因为我真的不希望将秘密签入源代码管理。这是完全可能的,并且 documentation 暗示,只要我避免更改模板中 SecretString
的虚拟值,秘密的值就不会在后续的 CloudFormation 堆栈更新中被触及。
因此,在 AWS 控制台中设置实际机密后,我需要触发 Lambda 函数的重新部署,以便 CloudFormation 解析新的机密值并在函数的环境中设置。我该怎么做?
执行 aws cloudformation deploy
失败并显示消息:没有要部署的更改。
我怀疑 CloudFormation 正在将模板的 "raw" 版本与最后部署的版本进行比较,而没有首先解析对 Secrets Manager 的引用。是这样吗?是否有一些技巧可以强制提前取消引用?
脚注:我很清楚以这种方式使用 Secrets Manager 会导致密钥值在 AWS Lambda 控制台中可见,并且从 Secrets Manager 获取值运行时将是更安全的方法。这恰好超出了我希望做的范围。
您说读取 Lambda 中的值超出范围,但这确实是正确的解决方案。它不仅提高了安全性,而且允许 Lambda 在密钥轮换时获取最新值。
如果您在处理程序外部读取机密(也就是说,在初始化期间),则读取次数会最小化。如果这是连接到数据库的 java lambda,您还可以使用 secrets manager jdbc wrapper 来自动获取密钥。
您可以在 AWS::Serverless::Function
资源上人为地更改 其他内容 以强制它在您进行部署时进行更新。
例如,时间戳:
Parameters:
DeployTimestamp: { Type: String }
Resources:
Function:
Type: AWS::Serverless::Function
Properties:
Environment:
Variables:
SECRET_KEY: !Sub '{{resolve:secretsmanager:${Secret}:SecretString:KEY}}'
SECRET_KEY_UPDATED: !Ref DeployTimestamp
假设您从脚本进行部署,那么您每次都会执行 aws cloudformation deploy --parameter-overrides "DeployTimestamp=$(date)"
之类的操作来更改值。
当然,这样做的缺点是该函数将更新每个部署,即使机密尚未更新。如果这让你感到困扰,你可以变得更有趣,并将 aws secretsmanager describe-secret --query LastChangedDate
作为参数而不是当前时间注入。