我可以强制 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 作为参数而不是当前时间注入。