Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I want to create the inbound rules of a security group in a cloud formation template. I want to open the 3306 port from many different IPs.

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

I know that the documentation says String as the CidrIp type but would it be possible to do something like this ["100.10.77.66/32", "100.10.66.66/32" , "101.10.77.66/32"] in order to avoid writing the same block many times?

like image 270
Kostas Demiris Avatar asked Apr 20 '16 09:04

Kostas Demiris


2 Answers

Afraid not, as the documentation states it only accepts String and not List therefore multiple blocks are required.

Think of it the same way as ingress rules are created within the web console, one new rule for each CIDR.

like image 125
Aeladru Avatar answered Sep 29 '22 12:09

Aeladru


Unfortunately, there's no iteration available through CloudFormation's Intrinsic Functions, and as you pointed out the AWS::EC2::SecurityGroupIngress resource itself only accepts a single String for its CidrIp property.

As an alternative, I would recommend choosing an intermediate format to compile down to CloudFormation template JSON using a preprocessor, if/when greater expressive power is needed. You can use a full-featured library like troposphere, but it's also easy enough to code up your own basic preprocessing layer to suit your use-case and programming-language/library preferences.

My current choice is a combination of YAML with embedded Ruby (ERB), mostly because I'm already familiar with them. Here's an example template.yml.erb file that would generate the example JSON above:

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 -%>

Here's a minimal preprocessor script, process_template.rb:

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

Running ruby ./process_template.rb template.yml.erb produces:

{
  "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
    }
  ]
}
like image 44
wjordan Avatar answered Sep 29 '22 12:09

wjordan