Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cloudformation Security Group configuration using list

I am defining a cloudformation stack where the security group should allow ingress traffic from specified IP addresses. I have defined these IP addresses as mapping and they will grow in future when we onboard new customers on our platform. My current cloudformation stack looks like

AWSTemplateFormatVersion: '2010-09-09'  
Description: Security group.

Parameters:
  VPCStackName:
    Type: String
    Description: The name of VPC stack

Mappings:
  # Security group configuration for different environments
  SecurityGroupConfiguration:
    PROD: 
      IPAddress: "149.250.241.202/32 149.250.241.202/32"
    NON-PROD: 
      IPAddress: "149.250.241.202/32, 149.250.241.204/32, 149.250.241.205/32"

Resources:

  # Add security groups and their ingress
  PublicSubnetSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Test security group
      VpcId: 
        Fn::ImportValue:
          !Sub "${VPCStackName}-vpcid"
      SecurityGroupIngress:
        - CidrIp: !FindInMap ['SecurityGroupConfiguration', 'PROD', 'IPAddress']
          IpProtocol: -1

This does not allow the SG to be created no matter I separate them by ' ', ',' or ';'.

2nd method I wanted to try was to define these mappings as a list and iterate them dynamically depending on number of elements configured. For PROD and NON-PROD the list will have different number of IP addresses, so I won't be able to define indexes. E.g. Production will have 4 IP addresses and Non-Prod might have only 2 IP addresses. If I define indexes for !Select, the same CFN template will not work for both the environments.

AWSTemplateFormatVersion: '2010-09-09'  
Description: Security group.

Parameters:
  VPCStackName:
    Type: String
    Description: The name of VPC stack

Mappings:
  # Security group configuration for different environments

  SecurityGroupConfiguration:
  PROD: 
    IPAddress: 
      - 149.250.241.202/32
      - 149.250.241.203/32
  NON-PROD: 
    IPAddress: 
      - 149.250.241.202/32
      - 149.250.241.204/32
      - 149.250.241.205/32

Resources:

  # Add security groups and their ingress
  PublicSubnetSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Test security group
      VpcId: 
        Fn::ImportValue:
          !Sub "${VPCStackName}-vpcid"
      SecurityGroupIngress:
        - CidrIp: for (i in SecurityGroupConfiguration)
            <Dynamically iterate over list to produce all the ip addresses>
            !Select [i, !FindInMap ['SecurityGroupConfiguration', 'PROD', 'IPAddress']]
          IpProtocol: -1

Is there a way to get around this problem?

like image 224
kk. Avatar asked Jun 03 '19 14:06

kk.


2 Answers

short answer: prefix-lists
A possible solution that completely avoids your problem is to create a prefix-list containing all the IPs (and can be modified at a later time) and instead reference that prefix-list in your SG. Future updates to your prefix-list takes effect immediately wihtout any modification to your live SG.
Please see Prefix lists for details.

Note: please do keep in mind your VPC limits if you set this up for a large number of IPs (see Amazon VPC quotas)

like image 105
Martin J Avatar answered Nov 10 '22 16:11

Martin J


AWS cloudformation's Custom resources enable you to write custom provisioning logic in templates that AWS CloudFormation runs anytime you create, update (if you changed the custom resource), or delete stacks.

You can use AWS Lambda-backed Custom Resources. When you associate a Lambda function with a custom resource, the function is invoked whenever the custom resource is created, updated, or deleted. AWS CloudFormation calls a Lambda API to invoke the function and to pass all the request data (such as the request type and resource properties) to the function.

The power and customizability of Lambda functions in combination with AWS CloudFormation you can update the security group in custom way.

There are some open source project which can help you write it quickly

  • https://github.com/stelligent/cloudformation-custom-resources
  • https://staging.binx.io/blog/2018/08/25/building-cloudformation-custom-resources-is-plain-and-simple/
like image 41
Ankit Gupta Avatar answered Nov 10 '22 15:11

Ankit Gupta