AWS CloudFormation:使用 resolve 具有动态引用的嵌套子会导致错误并且不执行解析以从 Parameter Store 获取值
Posted
技术标签:
【中文标题】AWS CloudFormation:使用 resolve 具有动态引用的嵌套子会导致错误并且不执行解析以从 Parameter Store 获取值【英文标题】:AWS CloudFormation: Nested Sub with Dynamic References using resolve causes error and doesn't execute resolve to get value from Parameter StoreAWS CloudFormation:使用 resolve 具有动态引用的嵌套子会导致错误并且不执行解析以从 Parameter Store 获取值 【发布时间】:2019-12-28 06:05:12 【问题描述】:我正在尝试使用 AWS CloudFormation 模板创建一个 EC2 实例,其中包含使用模板中的动态引用和跨堆栈引用生成的一些用户数据。 AWS Systems Manager Parameter Store 中有一个参数存储在Name:/MyCustomParameter
和Value:Test1
。
这个想法是将参数传递给模板堆栈(堆栈A),该堆栈引用另一个云形成堆栈(堆栈B)。堆栈 B 使用引用“StackB::ParameterStoreName”导出一个变量。堆栈 A 使用 Fn::ImportValue: 'StackB::ParameterStoreName'
获取它的值,以便它可以与动态引用方法一起使用,以使用 resolve:ssm:/MyCustomParameter:1
从 AWS SSM Parameter Store 获取它的值,并将其值传递给模板中的 UserData 字段。在此用例中尝试使用嵌套的 Fn::Sub:
函数时,我遇到了困难。
我尝试删除 |
管道并使用带有转义换行符的双引号,但这不起作用。
我还尝试使用不同类型的资源,它的属性在哪里起作用。下面是一个有效的代码示例。
Resources:
TestBucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName:
Fn::Sub:
- '$SSMParameterValue-12345'
- SSMParameterValue:
Fn::Sub:
- 'resolve:ssm:$SSMParameterName:1'
- SSMParameterName:
Fn::ImportValue:
!Sub '$CustomStack::ParameterStoreName'
以下是我当前代码的摘录:
Parameters:
CustomStack:
Type: "String"
Default: "StackB"
Resources:
MyCustomInstance:
Type: 'AWS::EC2::Instance'
Properties:
UserData:
Fn::Base64:
Fn::Sub:
- |
#!/bin/bash -e
#
# Bootstrap and join the cluster
/etc/eks/bootstrap.sh --b64-cluster-ca '$SSMParameterValue' --apiserver-endpoint '$Endpoint' '$ClusterName'"
- SSMParameterValue:
Fn::Sub:
- 'resolve:ssm:/$SSMParameterName:1'
- SSMParameterName:
Fn::ImportValue:
!Sub '$CustomStack::ParameterStoreName'
Endpoint:
Fn::ImportValue:
!Sub '$CustomStack::Endpoint'
ClusterName:
Fn::ImportValue:
!Sub '$CustomStack::ClusterStackName'
电流输出:
#!/bin/bash -e
#
# Bootstrap and join the cluster
/etc/eks/bootstrap.sh --b64-cluster-ca `resolve:ssm:MyCustomParameter:1` --apiserver-endpoint 'https://04F1597P0HJ11FQ54K0YFM9P19.gr7.us-east-1.eks.amazonaws.com' 'eks-cluster-1'
预期输出:
#!/bin/bash -e
#
# Bootstrap and join the cluster
/etc/eks/bootstrap.sh --b64-cluster-ca `Test1` --apiserver-endpoint 'https://04F1597P0HJ11FQ54K0YFM9P19.gr7.us-east-1.eks.amazonaws.com' 'eks-cluster-1'
【问题讨论】:
【参考方案1】:我认为这是因为解析是在 base64 中,也许......?当它处理该行时,它只会看到一个 base64 块,而不是 resolve... 代码。 “解析”在 !Function 之后处理,因为在代码运行之前无法解析它们。
为了解决这个问题,我添加了一个临时 SSM 参数:
eksCAtmp:
Type: "AWS::SSM::Parameter"
Properties:
Type: String
Value:
Fn::Join:
- ''
- - 'resolve:ssm:'
- Fn::ImportValue:
!Sub "$ClusterName-EksCA"
- ':1'
这会导入原始的 SSM 参数并摆脱“导入”并再次解析它的要求。所以现在你可以使用!GetAtt eksCAtemp.Value
例如:
UserData: !Base64
"Fn::Sub":
- |
#!/bin/bash
set -o xtrace
/etc/eks/bootstrap.sh $ClusterName --b64-cluster-ca $CA --apiserver-endpoint $endpoint --kubelet-extra-args '--read-only-port=10255'
/opt/aws/bin/cfn-signal --exit-code $? \
--stack $AWS::StackName \
--resource NodeGroup \
--region $AWS::Region
- endpoint:
Fn::ImportValue:
!Sub "$ClusterName-EksEndpoint"
CA: !GetAtt eksCAtmp.Value
(当然,如果他们允许跨堆栈导出超过 1024 个字符,我们就不需要在专用网络上启动 EKS。)
【讨论】:
【参考方案2】:你可以这样写:
UserData:
Fn::Base64:
Fn::Sub:
- |
#!/bin/bash -e
#
# Bootstrap and join the cluster
export SSMParameterValue=$(aws --region $AWS::Region ssm get-parameters --names $SSMParameterName --query 'Parameters[0].Value' --output text)
/etc/eks/bootstrap.sh --b64-cluster-ca \`$SSMParameterValue\` --apiserver-endpoint '$Endpoint' '$ClusterName'"
- SSMParameterName:
Fn::ImportValue:
!Sub '$CustomStack::ParameterStoreName'
Endpoint:
Fn::ImportValue:
!Sub '$CustomStack::Endpoint'
不要忘记您的 EC2 角色需要 ssm:GetParameters 权限。
【讨论】:
以上是关于AWS CloudFormation:使用 resolve 具有动态引用的嵌套子会导致错误并且不执行解析以从 Parameter Store 获取值的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法使用 cloudformation 修改 AWS 现有资源?
通过 cloudformation 使用 aws `cdk synth` 输出
使用 AWS CLI 将现有资源导入 CloudFormation
是否可以在 AWS::OpsWorks::Instance 资源中使用 AWS::CloudFormation::Init 和元数据?
使用 AWS CloudFormation 添加环境变量会重置 AWS Beanstalk 应用程序
如何修复与 AWS::CloudFormation::Init 一起创建 EC2 的 cloudformation 模板