0

根据 AWS 的说法,当使用 CloudFormation 部署需要机密(即密码或类似内容)的基础设施时,一种流行的解决方案是使用来自 SSM 的 Parameter Store 的 SecureStrings。

然而,尽管现有的CFN 文档逐步描述了如何在 CFN 模板中使用动态引用,但我无法设法利用 SecureStrings 的实际值。

假设存储在 SSM 参数存储中的现有 SecureString 的以下 JSON 表示:

{
  "MyRedshiftMasterUserPassword": {
    "value": "Abcd2019",
    "type": "SecureString"
  }
}

以及使用它的 YAML CFN 模板,如文档中所述:

Resources
  Redshift:
    Type: 'AWS::Redshift::Cluster'
    Properties:
      NodeType: dc2.large
      NumberOfNodes: !Ref RedshiftNodes
      ClusterType: multi-node
      AutomatedSnapshotRetentionPeriod: !Ref AutomatedSnapshotRetentionPeriod
      DBName: datawarehouse_v1
      MasterUsername: !Ref RedshiftMasterUsername
      MasterUserPassword: '{{resolve:ssm-secure:MyRedshiftMasterUserPassword:1}}'

上述解决方案不起作用,因此要么我错误地定义了模板,要么没有正确实现对这个功能的支持,考虑到它来自 AWS,这对我来说似乎很奇怪。

特别是,我遇到了以下所有最终都以UPDATE_FAILED堆栈形式出现的错误:

  1. 每当要解析的引用参数名称足够长时,CloudFormation 就会抱怨:

参数 MasterUserPassword 不是有效密码,因为它超过 64 个字符。(服务:AmazonRedshift;状态代码:400;错误代码:InvalidParameterValue;请求 ID:7be9bd43-2927-11e9-aa88-29bbdcae859e)

  1. 此外,即使特别提到可以在模板引用中使用斜线,/infrastructure/datawarehouse/redshift/MyRedshiftMasterUserPassword也会发出以下错误:

参数 MasterUserPassword 不是有效密码。只能使用除 '/'、'@'、'"'、''、'\'、''' 之外的可打印 ASCII 字符。(服务:AmazonRedshift;状态代码:400;错误代码:InvalidParameterValue)

因此,作为结果引用的 SecureString 似乎与 SSM ParameterStore 层次结构(带有斜杠的参数)不兼容。

  1. 此外,从参数名称中删除任何先前报告的无效字符,然后它会抱怨以下内容:

参数 MasterUserPassword 必须至少包含 1 个大写字母。(服务:AmazonRedshift;状态代码:400;错误代码:InvalidParameterValue;请求 ID:90a263bd-2929-11e9-80c0-ffcecf297c44)


最后,尽管在模板中使用基本的短非斜线Parameter name允许堆栈完成更新操作动态引用仍然不会发生,因为使用的实际值结果是提供的参数名称而不是由此引用的值,例如MyRedshiftMasterUserPassword而不是Abcd2019.

我知道也可以使用 AWS Secrets Manager,但它不是免费的。

4

1 回答 1

0

与 AWS 一起打开支持案例,请求就 CloudFormation 的这种特殊奇怪行为提供指导。

根据支持团队的说法,实际上这确实是 CloudFormation 服务的一个已知错误,但没有估计修复时间。SSM Parameter Store SecureString 参数的解析在 RedshiftMasterUserPassword 属性的特定情况下用作动态引用时,尽管在文档中引用,但未正确解析,而是使用参数名称。

或者,他们在问题得到解决的同时提供了 2 种解决方法:

  1. NoEcho从属性设置为 true的输入参数获取 Redshift 的“MasterUserPassword” 。NoEcho 属性允许您屏蔽密码值,并且您不需要将密码存储在模板文件中。但是,每次更新堆栈时,都需要输入密码作为输入参数。供您参考,下面的代码片段将很有用。

第二种选择,更通用:

  1. 在您的模板文件中定义一个Lambda 支持的自定义资源,该资源会查询 SSM 服务并将密码返回给 CloudFormation。在这种情况下,您需要为 lambda 函数编写自定义代码,该函数使用 AWS GetParameter API 调用来检索 SSM 安全字符串参数的值并将解密后的值返回给 CloudFormation。

其他支持的动态引用属性似乎工作正常。

于 2019-02-12T15:44:27.727 回答