将未知大小的安全组列表添加到EC2实例

Jon*_*o D 14 amazon-ec2 amazon-web-services aws-cloudformation

我们有一个CloudFormation模板,用于创建EC2实例和安全组(以及许多其他资源),但我们需要能够向同一个EC2实例添加一些其他预先存在的安全组.

我们遇到的问题是,预先存在的安全组的数量并不总是相同,我们希望有一个模板来处理所有情况.

目前,我们有一个输入参数,如下所示:

"WebTierSgAdditional": {
  "Type": "String",
  "Default": "",
  "Description": ""
}
Run Code Online (Sandbox Code Playgroud)

我们将此参数传递给逗号分隔的预先存在的安全组字符串,例如'sg-abc123,sg-abc456'.

EC2实例的SecurityGroup标记如下所示:

"SecurityGroups": [
  {
    "Ref": "WebSg"
  },
  {
    "Ref": "WebTierSgAdditional"
  }
]
Run Code Online (Sandbox Code Playgroud)

使用此代码,在创建实例时,我们会在AWS控制台中收到此错误:

必须对所有安全组使用group-id或group-name,而不是同时使用

上面的'WebSg'参考是在模板中其他地方创建的安全组之一.如果我们通过输入参数传入组名列表而不是组ID列表,则会出现同样的错误.

当我们将输入参数的"类型"字段更改为"CommaDelimitedList"时,我们会收到错误消息:

属性值SecurityGroups的类型必须是List of String

它显然无法使用字符串连接列表以使其成为新列表.

当参数只包含一个sg id时,所有内容都会成功创建,但是,我们需要能够添加多个sg id.

我们Fn::Join在SecurityGroups标记中尝试了许多不同的使用组合,但似乎没有任何效果.我们真正需要的是某种"爆炸"功能,用于从参数字符串中提取单个id.

有谁知道一个很好的方法让这个工作?

sor*_*han 10

正如您所知,问题是您需要发送字符串列表作为安全组,虽然CloudFormation为您提供了将字符串列表连接到单个分隔字符串的方法,但它不提供简单的方法用于将分隔的字符串拆分为字符串列表.

不幸的是,我知道如何做到这一点的唯一方法是使用嵌套堆栈.您可以使用参数类型"CommaDelimitedList"将逗号分隔的字符串拆分为字符串列表.

基本方法是这样的:

  1. 在您的云信息模板中创建安全组.
  2. 使用Fn :: Join将安全组ID与安全组列表合并.
  3. 将该列表传递给嵌套堆栈(AWS :: CloudFormation :: Stack类型的资源).
  4. 将该参数作为单独模板中的"CommaDelimitedList"类型.
  5. 将参数ref传递给EC2实例声明.

我用以下2个模板对它进行了测试,结果正常:

主要模板:

{
    "AWSTemplateFormatVersion": "2010-09-09",                                                                                                  
    "Parameters" : {
        "SecurityGroups" : {                                                                        
            "Description" : "A comma separated list of security groups to merge with the web security group",
            "Type" : "String"
        }
    },
    "Resources" : {
        "WebSg" : ... your web security group here,
        "Ec2Instance" : {
            "Type" : "AWS::CloudFormation::Stack",
            "Properties" : {
                "TemplateURL" : "s3 link to the other stack template",
                "Parameters" : {
                    "SecurityGroups" : { "Fn::Join" : [ ",", [ { "Ref" : "WebSg" }, { "Ref" : "SecurityGroups" } ] ] },
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

嵌套模板(由上面的"TemplateURL"链接):

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Parameters" : {
        "SecurityGroups" : {
            "Description" : "The Security Groups to launch the instance with",
            "Type" : "CommaDelimitedList"
        },
    }
    "Resources" : {
        "Ec2Instance" : {
            "Type" : "AWS::EC2::Instance",
            "Properties" : {                                     
                ... etc           
                "SecurityGroupIds" : { "Ref" : "SecurityGroups" }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我很想知道是否有更好的方法来做到这一点.如你所说,它真的需要一个爆炸功能.


Ala*_*vey 8

AWS 于20171月推出了Fn :: Split,现在可以实现.它并不漂亮,但你实际上是将两个列表转换为字符串,然后将字符串转换回列表.Fn::JoinFn::Split

Parameters:

    WebTierSgAdditional:
        Type: CommaDelimitedList
        Default: ''

Conditions:

    HasWebTierSgAdditional: !Not [ !Equals [ '', !Select [ 0, !Ref WebTierSgAdditional ] ] ]

Resources:

    WebSg:
        Type: AWS::EC2::SecurityGroup
        Properties:
            # ...

    Ec2Instance:
        Type: AWS::EC2::Instance
        Properties:
            # ...
            SecurityGroupIds: !Split
                  - ','
                  - !Join
                      - ','
                      -   - !Ref WebSg
                          - !If [ HasWebTierSgAdditional, !Join [ ',', !Ref WebTierSgAdditional ], !Ref 'AWS::NoValue' ]
Run Code Online (Sandbox Code Playgroud)

WebTierSgAdditional以列表开头,但转换为字符串,每个项目用逗号分隔!Join [ ',', !Ref WebTierSgAdditional ].这包含在另一个包含的列表中,!Ref WebSg该列表也被转换为字符串,每个项目用逗号分隔.!Split将采用字符串并将项目拆分为以逗号分隔的列表.