AWS CloudFormation 模板:是否可以将许多 CidrIp 添加为列表?

AWS CloudFormation template: Is it possible to add many CidrIp as a list?

我想在云编队模板中创建安全组的入站规则。我想从许多不同的 IP 打开 3306 端口。

    "SecurityGroupIngress": [
            {
                "IpProtocol": "tcp",
                "CidrIp": "0.0.0.0/0",
                "FromPort": "3306",
                "ToPort": "3306"
            }

我知道文档说 String 是 CidrIp 类型,但是是否可以这样做 ["100.10.77.66/32", "100.10.66.66/32" , "101.10.77.66/32"] 以避免多次写入相同的块?

恐怕不会,因为文档指出它只接受字符串而不接受列表,因此需要多个块。

将其视为在 Web 控制台中创建入口规则的方式,每个 CIDR 一个新规则。

不幸的是,CloudFormation 的 Intrinsic Functions, and as you pointed out the AWS::EC2::SecurityGroupIngress 资源本身没有可用的迭代,它的 CidrIp 属性.

只接受一个 String

作为替代方案,我建议选择一种中间格式,使用预处理器编译成 CloudFormation 模板 JSON,if/when 需要更强大的表达能力。您可以使用像 troposphere 这样的全功能库,但编写您自己的基本预处理层代码以适应您的用例和 programming-language/library 偏好也很容易。

我目前的选择是 YAML with embedded Ruby (ERB) 的组合,主要是因为我已经熟悉它们了。这是一个示例 template.yml.erb 文件,它将生成上面的示例 JSON:

SecurityGroupIngress:
<% ["100.10.77.66/32", "100.10.66.66/32" , "101.10.77.66/32"].each do |cidr| -%>
- IpProtocol: tcp
  CidrIp: <%=cidr%>
  FromPort: 3306
  ToPort: 3306
<% end -%>

这是一个最小的预处理器脚本,process_template.rb:

require 'erb'
require 'yaml'
require 'json'
puts JSON.pretty_generate(YAML.load(ERB.new(ARGF.read, nil, '-').result))

运行 ruby ./process_template.rb template.yml.erb 产生:

{
  "SecurityGroupIngress": [
    {
      "IpProtocol": "tcp",
      "CidrIp": "100.10.77.66/32",
      "FromPort": 3306,
      "ToPort": 3306
    },
    {
      "IpProtocol": "tcp",
      "CidrIp": "100.10.66.66/32",
      "FromPort": 3306,
      "ToPort": 3306
    },
    {
      "IpProtocol": "tcp",
      "CidrIp": "101.10.77.66/32",
      "FromPort": 3306,
      "ToPort": 3306
    }
  ]
}

基于的方法,这里有一种类似的方法,您可以在与 ERB 模板分离的文件中指定 CidrIp。首先,创建一个 ERB 文件。例如,让我们看看 sgi-trusted-ip-range.erb:

Type: "AWS::EC2::SecurityGroupIngress"
<%- Dir.glob("trusted-ip-range/cidr-*.csv").map {|f| File.readlines(f)}.flatten.map(&:strip).each do |cidr| -%>
- IpProtocol: tcp
  CidrIp: <%=cidr%>
  FromPort: 80
  ToPort: 80
- IpProtocol: tcp
  CidrIp: <%=cidr%>
  FromPort: 443
  ToPort: 443
<%- end -%>

根据您的要求放置 CIDR 列表文件,并遵循命名约定 trusted-ip-range/cidr-*.csv,其中内容例如:

100.10.77.66/32
100.10.66.66/32
101.10.77.66/32

然后,一行生成YAML文件:

ruby -r erb -e 'ERB.new(ARGF.read, nil, "-").run' sgi-trusted-ip-range.erb

此外,您可以像下面这样验证生成的 YAML 文件:

aws cloudformation validate-template --template-body "file://__PATH_TO_FILE__.yml"

我很好奇为什么没有提到 Cloudformation 自定义资源的答案。 您仍然可以使用 lambda 函数创建自己的自定义安全组,该函数 creates/deletes 基于您的云形成状态(创建、更新、删除)的安全组。 我写了一个简单的自定义资源here,大家觉得方便可以随意修改自定义资源参数。 然后您可以在创建堆栈时输入逗号分隔的 cidr 块。 您可以使用以下方式在实例(或其他资源)上引用此安全组:
!GetAtt CustomSG.SecGroupId

我不确定为什么没有提到前缀列表。您可以创建包含所有 CIDR 的前缀列表,并在 CF 模板中将前缀列表 ID 作为安全组源。例子

PrefixList:
    Type: AWS::EC2::PrefixList
    Properties:
      PrefixListName: "Name of PL"
      AddressFamily: "IPv4"
      MaxEntries: 2 # the number of CIDR's you want to add
      Entries:
        - Cidr:  "10.10.0.0/16"
          Description: "CIDR1"
        - Cidr: "10.100.0.0/16"
          Description: "CIDR2"
      Tags:
        - Key: "Name"
          Value: "PL

请完成下面的link。

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-prefixlist.html