How to Create Security Group in AWS using CloudFormation

How to Create Security Group in AWS using CloudFormation

How to Create Security Group in AWS using CloudFormation

Dear reader, I hope you are doing great. In this post, I will help you create security group in AWS using CloudFormation.

I will show you various ways in which you can create/define the backbone of a security group i.e inbound/outbound rules. Additionally, I will explain why should you use one way over the other.

After that, I will share the AWS security group CloudFormation example in YAML and JSON.

So are you ready to explore the AWS security group using CloudFormation?

Alright !!!

Let’s start with understanding the security group on AWS.

Don’t want to miss any posts from us? join us on our Facebook group, and follow us on Facebook, Twitter, LinkedIn, and Instagram. You can also subscribe to our newsletter below to not miss any updates from us.

What is a Security Group?

A security group is a virtual firewall that controls the incoming and outgoing traffic for the resource it is attached to.

For example – When you attach a security group to an EC2 instance, it controls what traffic can reach your instance and what traffic is allowed to leave your instance.

Things You Should Know About Security Group

  • Your VPC comes with a default security group.
  • You can create additional security groups as per your need.
  • Your security group and the resource you attach it to should be in the same VPC.
  • You can attach more than one security group to your resource such as an EC2 instance.
  • You add rules to your security group to control traffic based on protocols and port numbers.
  • Rules are of two types- Inbound and Outbound, As the name says they control inbound(incoming traffic to resource) and outbound(outgoing traffic from resource) traffic respectively.
  • By default, outbound rule allows all traffic on all protocols. You can create your own outbound rule to remove the default outbound rule.

Suggested Read: AWS Security Group vs NACL(Network Access Control List)

Steps to Create Security Group in AWS using CloudFormation

By now we know a bit about the security group and we are ready to create our first security group using CloudFormation. Let’s see the step-by-step instruction to create a security group on AWS using CloudFormation.

Looking for the best course to master AWS CloudFormation? Here is what I used to get myself kickstarted: AWS CloudFormation Master Class

Step 1: Provide proper permission

If you are not an admin user, you should at least have the below permissions to be able to create/manage security groups and group rules.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1669573990083",
      "Action": [
        "ec2:AuthorizeSecurityGroupEgress",
        "ec2:AuthorizeSecurityGroupIngress",
        "ec2:CreateSecurityGroup",
        "ec2:DeleteSecurityGroup",
        "ec2:DescribeSecurityGroupRules",
        "ec2:DescribeSecurityGroups",
        "ec2:ModifySecurityGroupRules",
        "ec2:RevokeSecurityGroupEgress",
        "ec2:RevokeSecurityGroupIngress"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

However, If you are not able to figure out the correct set of permission, you can start with ec2:* and later modify your policy to follow the least privilege principle. Additionally, you will also need cloudformation:* to be able to do CloudFormation stack creation, updation etc.

Step 2: Prepare a template

You can use YAML or JSON for your template. I prefer YAML for writing my templates. But don’t worry, If you want it in JSON, I will provide a JSON template as well.

On the other hand, you yourself can convert your template from JSON to YAML and Vice Versa.

How to Create CloudFormation Template for Security Group on AWS

To create a security group on AWS, all you need is a AWS::EC2::SecurityGroup  resource like below.

Type: AWS::EC2::SecurityGroup
Properties: 
  GroupDescription: String
  GroupName: String
  SecurityGroupEgress: 
    - Egress
  SecurityGroupIngress: 
    - Ingress
  Tags: 
    - Tag
  VpcId: String

Few things to note there –

  • GroupDescription is for information or better readability purposes but it’s a mandatory parameter.
  • GroupName is the name of your security group and is not mandatory. If you don’t provide a name, CloudFormation will name your security group.
  • SecurityGroupEgress defines the outbound rule for your security and SecurityGroupIngress defines the inbound rule for the security group.
  • The above parameters define the rule embedded in the resource. You can use the separate resources AWS::EC2::SecurityGroupIngress and AWS::EC2::SecurityGroupEgress to do the same.
  • You can use the Tags parameter to specify a tag if you need it.
  • VpcId is The ID of the VPC for the security group.

Ideally, the template to create a simple security group with minimal parameters looks like below.

Resources:
  DemoSG:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupDescription: A Security Group for Demo-EC2

As I said, GroupDescription is mandatory and if you don’t specify it, you get an error like-

Property GroupDescription cannot be empty.

Important Note:

If you create a security group using the above minimal template, by default it will have no inbound rule which means any incoming traffic is not allowed. By default, an outbound rule gets attached which allows all outbound traffic.

This is what the inbound and outbound section looks like-

How to Create Security Group in AWS using CloudFormation 1
How to Create Security Group in AWS using CloudFormation 2

Also since we have not specified any VpcId, by default it gets created in the default VPC. Please note that you can attach a security group to resources in the same VPC only.

Let’s modify this security group template to make it more usable by proving an inbound/outbound rule.

Template to Create Security Group in AWS using CloudFormation: YAML

When it comes to defining inbound /outbound rules, you can embed them in the security group resource or can use separate resources AWS::EC2::SecurityGroupIngress and AWS::EC2::SecurityGroupEgress

The difference between the two is that if you want to cross-reference two security groups in the ingress and egress rules of those security groups, using the embedded ingress and egress rules in the AWS::EC2::SecurityGroup will result in a circular dependency.

Which one to use?

Usually, stick to using SecurityGroupIngress and SecurityGroupEgress parameters of AWS::EC2::SecurityGroup resource for the usual use-case. However, if you have a specific use case like you want to cross-reference two security groups, use the separate resources to avoid circular dependency

AWS Security Group Inline Inbound Rule Example using CloudFormation

AWSTemplateFormatVersion: 2010-09-09
Description: CloudFormation template for security group 

Parameters:
  VpcId:
    Type: String
    Description: VpcId
    Default: vpc-b19b4bda
    
Resources:
  DemoSG:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupDescription: A Security Group for Demo-EC2
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0

Outputs:
  SecurityGroupId:
    Description: Security Group Id
    Value: !GetAtt DemoSG.GroupId
  VpcId:
    Description: VpcId in Which SG is there
    Value: !GetAtt DemoSG.GroupId
Description of SecurityGroupIngress and SecurityGroupEgress

As you can see in the above template, we have used limited parameters like IpProtocol, FromPort, ToPort and CidrIp. However, there are more parameters available to you as shown below.

SecurityGroupIngress parameter:

This parameter takes these sub-parameters.

  CidrIp: String
  CidrIpv6: String
  Description: String
  FromPort: Integer
  IpProtocol: String
  SourcePrefixListId: String
  SourceSecurityGroupId: String
  SourceSecurityGroupName: String
  SourceSecurityGroupOwnerId: String
  ToPort: Integer

You can read more about them on AWS official website. However please note that you must specify only one of the following properties: CidrIpCidrIpv6SourcePrefixListIdSourceSecurityGroupId, or SourceSecurityGroupName.

You must specify a source security group or a CIDR range.

SecurityGroupEgress parameter:

  CidrIp: String
  CidrIpv6: String
  Description: String
  DestinationPrefixListId: String
  DestinationSecurityGroupId: String
  FromPort: Integer
  IpProtocol: String
  ToPort: Integer

Same as above, here you must specify only one of the following properties: CidrIpCidrIpv6DestinationPrefixListId, or DestinationSecurityGroupId.

You must specify a destination security group or a CIDR range. You can read more about the egress rule here.

Let’s see how to define the inbound/outbound rules as a separate resource.

The below template shows AWS::EC2::SecurityGroupIngress and AWS::EC2::SecurityGroupEgress examples. We are still using the CIDR only here. Later we will see a security group reference example as well.

AWSTemplateFormatVersion: 2010-09-09
Description: CloudFormation template for security group 

Parameters:
  VpcId:
    Type: String
    Description: VpcId
    Default: vpc-b19b4bda
    
Resources:
  DemoSG:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupDescription: A Security Group for Demo-EC2
      VpcId: !Ref VpcId
      
  DemoSgIngress:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref DemoSG
      IpProtocol: tcp
      FromPort: 443
      ToPort: 443
      CidrIp: 0.0.0.0/0
      
  DemoSgEgress:
    Type: AWS::EC2::SecurityGroupEgress
    Properties:
      GroupId: !Ref DemoSG
      IpProtocol: tcp
      FromPort: 443
      ToPort: 443
      CidrIp: 0.0.0.0/0

Outputs:
  SecurityGroupId:
    Description: Security Group Id
    Value: !GetAtt DemoSG.GroupId
  VpcId:
    Description: VpcId in Which SG is there
    Value: !GetAtt DemoSG.GroupId

Template to Create Security Group in AWS using CloudFormationJSON

CloudFormation Template with embedded inline inbound/outbound rule

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "CloudFormation template for security group",
    "Parameters": {
        "VpcId": {
            "Type": "String",
            "Description": "VpcId",
            "Default": "vpc-b19b4bda"
        }
    },
    "Resources": {
        "DemoSG": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": "A Security Group for Demo-EC2",
                "VpcId": {
                    "Ref": "VpcId"
                },
                "SecurityGroupIngress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 443,
                        "ToPort": 443,
                        "CidrIp": "0.0.0.0/0"
                    }
                ],
                "SecurityGroupEgress": [
                    {
                        "IpProtocol": "tcp",
                        "FromPort": 443,
                        "ToPort": 443,
                        "CidrIp": "0.0.0.0/0"
                    }
                ]
            }
        }
    },
    "Outputs": {
        "SecurityGroupId": {
            "Description": "Security Group Id",
            "Value": {
                "Fn::GetAtt": [
                    "DemoSG",
                    "GroupId"
                ]
            }
        },
        "VpcId": {
            "Description": "VpcId in Which SG is there",
            "Value": {
                "Fn::GetAtt": [
                    "DemoSG",
                    "GroupId"
                ]
            }
        }
    }
}

Template with separate inline inbound/outbound rule resource

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description": "CloudFormation template for security group",
    "Parameters": {
        "VpcId": {
            "Type": "String",
            "Description": "VpcId",
            "Default": "vpc-b19b4bda"
        }
    },
    "Resources": {
        "DemoSG": {
            "Type": "AWS::EC2::SecurityGroup",
            "Properties": {
                "GroupDescription": "A Security Group for Demo-EC2",
                "VpcId": {
                    "Ref": "VpcId"
                }
            }
        },
        "DemoSgIngress": {
            "Type": "AWS::EC2::SecurityGroupIngress",
            "Properties": {
                "GroupId": {
                    "Ref": "DemoSG"
                },
                "IpProtocol": "tcp",
                "FromPort": 443,
                "ToPort": 443,
                "CidrIp": "0.0.0.0/0"
            }
        },
        "DemoSgEgress": {
            "Type": "AWS::EC2::SecurityGroupEgress",
            "Properties": {
                "GroupId": {
                    "Ref": "DemoSG"
                },
                "IpProtocol": "tcp",
                "FromPort": 443,
                "ToPort": 443,
                "CidrIp": "0.0.0.0/0"
            }
        }
    },
    "Outputs": {
        "SecurityGroupId": {
            "Description": "Security Group Id",
            "Value": {
                "Fn::GetAtt": [
                    "DemoSG",
                    "GroupId"
                ]
            }
        },
        "VpcId": {
            "Description": "VpcId in Which SG is there",
            "Value": {
                "Fn::GetAtt": [
                    "DemoSG",
                    "GroupId"
                ]
            }
        }
    }
}

A small example of a security group referencing another security group in CloudFormation:

  DemoSG:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupDescription: A Security Group for Demo-EC2
      VpcId: !Ref VpcId
  SGingress:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref DemoSG
      IpProtocol: tcp
      FromPort: '0'
      ToPort: '65535'
      SourceSecurityGroupId: !Ref DemoSG

In the above template, GroupId means the ID of the security group to which this rule is gonna be added. SourceSecurityGroupId means the ID of the security group from which inbound traffic is allowed. Self-reference here means any compute resources in this security group can communicate with any other compute resource in the same security group on the specified port.

Step3: Create a Stack using the prepared template

Now, we know the basics and we have the template so let’s go and create the stack.

In this section, we are creating the stack from the AWS console. However, you can use my previous post on How to Deploy a CloudFormation Template on AWS using CLI to create it using CLI.

  1. Grab the YAML or JSON template from above at your convenience.
  2. Save the template with .yml or .json as per the choice of template and follow the below steps.
  3. Login to AWS Management Console, navigate to CloudFormation and click on Create stack.
  4. Click on “Upload a template file”, upload your saved .yml  or .json file and click Next
  5. Enter the stack name and click on Next. In the configuration, keep everything as default and click on Next.
  6. In the events tab of the stack, you can view the status.
  7. Once the stack is successfully created, you can click on the Resources tab in the CloudFormation stack to see the created resource. Click on it to verify the details of the created resource.
  8. Also, you can check the output tab of your CloudFormation stack to view the security group Id and VpcId.
How to Create Security Group in AWS using CloudFormation 3

Clean Up

If you are creating this security queue just for learning purposes. Don’t forget to delete your CloudFormation stack so that your security is deleted.

Happy Learning !!!

Conclusion:

In this post, we learnt how to create security group in AWS using CloudFormation. We also learnt some important points such as-

  • GroupDescription is the only parameter while creating a security group using CloudFormation.
  • We create inbound/outbound rules to control traffic.
  • By default, an outbound rule gets created that allows all the traffic.
  • You can specify your own outbound traffic to remove the default one and control it as per your requirement.
  • Inbound/outbound rules can either be embedded in the resource. Or it can be defined separately using AWS::EC2::SecurityGroupIngress and AWS::EC2::SecurityGroupEgress resources respectively.
  • Using separate resources has advantages when cross-referencing security groups to avoid cyclic dependency.

You can also check my post on How to Create an EC2 instance using CloudFormation to see how a security group is used in a resource.

I hope you found this post helpful. Feel free to drop your questions in the comment section.

Enjoyed the content?

Subscribe to our newsletter below to get awesome AWS learning materials delivered straight to your inbox.

Don’t forget to motivate me by-

Suggested Read:

Leave a Reply

Your email address will not be published. Required fields are marked *