Terraform

Managing AWS Security Groups Through Terraform

Managing AWS Security Groups through Terraform, Network Security and more

As per the Divvy Cloud report, cloud misconfiguration breaches cost companies around the world an estimated 5 trillion in 2018 and 2019.

Many organizations fail to install adequate security measures, which are critical for protecting the cloud against breaches and attacks. Having an understanding of security and installing the appropriate security measures minimizes threats and keeps the cloud secure.

Security is a shared responsibility between AWS and the customer, where AWS is responsible for the security of the cloud, and the customers are responsible for security in the cloud.

AWS provides many security features, and VPCs are one of the most important. They let us create an isolated private cloud within the public cloud to protect resources from direct access.

In this article, we will go through:

  1. Virtual Private Cloud (VPC)
  2. Security Groups
  3. Creating Our Own Security Group
  4. Important Characteristics of Security Groups
  5. Managing Security Groups Through Terraform
  6. How to Use Existing Security Groups
  7. Applications of Security Groups
  8. Security groups vs. NACL
  9. Security groups and compliance

Virtual Private Cloud (VPC)

Virtual Private Cloud (VPC) is one of the fundamental building blocks of AWS. VPCs are private virtual networks that resemble traditional networks and provide secure, isolated environments to host and protect AWS resources like EC2 instances.

Security for the resources within the VPC can be configured using security groups and a network access control list (NACL).

Let’s understand how we can use them to protect resources within VPC and improve the overall security posture.

Read more about how to build AWS VPC using Terraform and how to create AWS EC2 instance using Terraform.

Security Groups

What are security groups?

Security groups are one of the most important pillars that support VPC security. They are software-defined network firewalls defined inside a VPC that allow or deny traffic to resources based on the inbound and outbound rules.

They support stateful Layer 3 (Network layer) and Layer 4 (Transport layer) filtering capabilities.

At the resource level, security groups work to secure the flow of traffic allowed to leave and reach them. They serve as the final line of defense.

They are most commonly associated with EC2 instances, but their applications are not limited to them. They are widely used with a variety of other services such as CodeBuild, EKS, and so on.

The figure below shows how security groups secure traffic flow to and from resources.

security group

What makes up a security group?

A security group is composed of rules. A rule consists of the following components:

  • Protocol
  • Port range
  • Source
  • Destination

A security group has separate rule sets for incoming and outgoing traffic.

An inbound rule consists of a protocol, a port(s), and a source.

For example, the below rule allows all traffic to reach resources associated with the security group.

security group - inbound rule

An outbound rule consists of a protocol, a port(s), and a destination.

For example, the below rule allows all traffic to leave resources associated with the security group.

security group - outbound rule

Let us inspect an existing security group to understand the rules better.

Exploring the default security group

Let us inspect the default security group to understand what the rules look like.

  1. Open the EC2 dashboard.
Security groups - EC2 dashboard
  1. Click on “Security Groups” in the left nav under “Networks and Security”.
  2. Explore the inbound and outbound rules for the default security group and other details.
default security group details

Key observations

  1. The default security group is associated with a VPC. The VPC ID can be found under the “VPC ID” tab.
  2. By default, the security group has one inbound and one outbound rule.
  3. All traffic can reach the associated resources thanks to the inbound rule.
  4. The outbound rule allows all traffic destined for everywhere (denoted by 0.0.0.0) to leave the associated resources.

We can always create new security groups with whatever rules we need. In the following section, we will learn how to do so.

Note: Please keep in mind that we can only create 2500 security groups per region.

Security consideration: Keep the number of security groups to a minimum to avoid making mistakes when managing too many security groups.

Creating Our Own Security Group

  1. Navigate to the “Security groups” panel.
  2. Click the “Create security group” button to create a new security group.
  3. Give the security group a name as web-server-sg and a description as Allow SSH to the web server.

Note: The name of the security group has to be unique within the VPC and cannot exceed 255 characters. Another thing to keep in mind is that the security group’s name cannot start with sg-.

create security group
  1. For the time being, do not add any inbound rules and proceed with the suggested outbound rule, which allows all traffic to flow everywhere (0.0.0.0).
  2. Finally, click on the “Create security group” button.
first security group

Congratulations! You have created your first security group 🎉

Security groups are only effective when attached to an AWS resource. Next, we will attach it to an EC2 instance to see it in action.

Attaching Security Groups to AWS Resources

In this tutorial, we will create an EC2 instance and attach the newly created security group to it. We will then try to connect to this instance via SSH.

Attaching a security group to an EC2 instance

  1. Navigate to the EC2 dashboard and click on the “Launch instances” button.
  2. Assign the instance a name as web-server.
  3. Choose any Amazon Machine Image (AMI) and architecture.
attaching a security group to an EC2 instance
  1. Select the instance type as t2.nano.
  2. Create a new key and name it web-server-key. The key will be downloaded automatically. We will use it later to SSH into our instance.
  3. Make sure to select the default VPC and a public subnet under “Network settings
  4. Enable the “Auto-assign public IP” option.
security groups auto-assign public IP
  1. Under the “Firewall (security groups)” tab, choose the option “Select existing security group” and select the security group we created earlier named web-server-sg.
firewall (security groups)
  1. Leave all other options unchanged and launch the instance.

With the security group now attached to our EC2 instance, let us try to connect to it via SSH.

Connecting to the EC2 instance via SSH

Open the details of the newly created EC2 instance and copy the public IP address.

connecting to the EC2 instance via SSH
  1. Open a terminal and modify the permissions for the web-server-key.pem file we downloaded earlier to allow read and write permission for the owner using the below command.
$ chmod 600 web-server-key.pem
  1. Next, let us try to connect to the EC2 instance with our pem key using the below command.
$ ssh -i web-server-key.pem ec2-user@44.211.190.174
# The username might changed based on the OS that you have chosen for your instance

After a while, the SSH request times out with the following error.

security groups ssh request time out

This is expected as our request is being blocked by the security group that we have attached to the EC2 resource. Remember that the security group we created does not yet have any inbound rules.

We can resolve this issue by configuring an inbound rule to allow incoming traffic on port 22 (SSH) from our IP address.

Adding rules to an existing security group

    1. Open the security groups panel and select the security group attached to our EC2 instance named web-server-sg.
    2. Under the “Inbound rules” tab, click the “Edit inbound rules” button, followed by the “Add rule” button.
Adding rules to an existing security group
  1. Choose SSH as the protocol and My IP as the source (allowing SSH through your IP only). Optionally, add the description as Allow SSH from my network.

Security consideration: For protocols such as SSH and RDP, only specific IP addresses should be allowed. Specifying 0.0.0.0 opens access to everyone, which is a security risk.

It should be noted that the source and destination do not have to be IP addresses. Other security groups or prefixes can also be used.

security groups edit inbound rules
  1. Save the rule and attempt to reconnect to the EC2 instance via SSH.

Reconnecting to the EC2 instance via SSH

We’ll use the same SSH command as before to see if we can connect after adding the inbound rule to the security group.

$ ssh -i web-server-key.pem ec2-user@44.211.190.174
reconnecting to the EC2 instance via SSH

Awesome! We successfully connected when we added an inbound rule for SSH.

You can also try switching to a different network to confirm that the security group is blocking the traffic.

In the following sections, we’ll go over some of the key characteristics of security groups, as well as how to manage security groups with Terraform.

Important Characteristics of Security Groups

When working with security groups, it is critical to be aware of a few key characteristics.

  • There can only be “allow rules” in security groups, not “deny rules”
    AWS blocks all traffic to resources associated with security groups by default. The allow rules filter and allow traffic that is relevant.
  • A resource can have multiple security groups attached to it
    When multiple security groups are attached to a single resource, all rules are aggregated to form a single rule set that determines whether or not the traffic is allowed.
  • Security groups are stateful
    Being stateful means that with an outbound rule that allows traffic to flow out of the resource also allows the response to reach back regardless of whether an inbound rule is present or not. To better understand this analogy, please refer to this StackOverflow answer.

Managing Security Groups Through Terraform

Handling infrastructure at scale manually is an extremely difficult task. Terraform and other IaC tools make it much easier for us to create and manage infrastructure at scale thanks to their declarative approach and state management.

Let’s look at how we can easily create and manage security groups with Terraform.

You will need to have Terraform installed on your machine and your AWS credentials configured in the shell to follow this tutorial.

Note: We will keep using the same main.tf file and make changes to it.

You can also take a look at how platforms like Spacelift can help you and your organization fully manage cloud resources within minutes. Spacelift is a CI/CD platform for infrastructure-as-code that supports tools like Terraform, Pulumi, Kubernetes, and more. For example, it enables policy-as-code, which lets you define policies and rules that govern your infrastructure automatically. You can even invite your security and compliance teams to collaborate on and approve certain workflows and policies for parts that require a more manual approach.

Creating a security group

We’ll set up a security group with an inbound rule that allows only HTTPS traffic and an outbound rule that allows all traffic.

  1. Create a file with the name as main.tf and copy the below HCL code snippet to this file.
terraform {
 required_providers {
   aws = {
     source  = "hashicorp/aws"
     version = "~> 4.0"
   }
 }
}

provider "aws" {
 region = "us-east-1"
}

data "aws_vpc" "default" {
 default = true
}

resource "aws_security_group" "web_server_sg_tf" {
 name        = "web-server-sg-tf"
 description = "Allow HTTPS to web server"
 vpc_id      = data.aws_vpc.default.id

ingress {
   description = "HTTPS ingress"
   from_port   = 443
   to_port     = 443
   protocol    = "tcp"
   cidr_blocks = ["0.0.0.0/0"]
 }

egress {
   from_port   = 0
   to_port     = 0
   protocol    = "-1"
   cidr_blocks = ["0.0.0.0/0"]
 }
}
  1. Run the terraform plan command in the terminal where the file resides. The plan should look something like the one below.
Terraform will perform the following actions:
# aws_security_group.web_server_sg_tf will be created
 + resource "aws_security_group" "web_server_sg_tf" {
     + arn                    = (known after apply)
     + description            = "Allow HTTPS to web server"
     + egress                 = [
         + {
             + cidr_blocks      = [
                 + "0.0.0.0/0",
               ]
             + description      = ""
             + from_port        = 0
             + ipv6_cidr_blocks = []
             + prefix_list_ids  = []
             + protocol         = "-1"
             + security_groups  = []
             + self             = false
             + to_port          = 0
           },
       ]
     + id                     = (known after apply)
     + ingress                = [
         + {
             + cidr_blocks      = [
                 + "0.0.0.0/0",
               ]
             + description      = "HTTPS ingress"
             + from_port        = 443
             + ipv6_cidr_blocks = []
             + prefix_list_ids  = []
             + protocol         = "tcp"
             + security_groups  = []
             + self             = false
             + to_port          = 443
           },
       ]
     + name                   = "web-server-sg-tf"
     + name_prefix            = (known after apply)
     + owner_id               = (known after apply)
     + revoke_rules_on_delete = false
     + tags_all               = (known after apply)
     + vpc_id                 = "vpc-60f8391a"
   }
Plan: 1 to add, 0 to change, 0 to destroy.
  1. Run terraform apply to deploy the security group once the plan has been verified.
creating a security group - terraform

Great work! We have successfully deployed a new security group through Terraform 🎉

Adding rules to security groups

There are two ways to add rules to a security group in Terraform:

  • Inline rules: Rules defined with the aws_security_group terraform resource
  • Standalone rules: Rules defined separately using the aws_security_group_rule terraform resource

Note: Keep in mind that these are the two ways to add rules to a security group through Terraform, which at the end of the day, correspond to the same thing on AWS.

Terraform advises that inline rules should not be used in conjunction with standalone rules. Using both of them together can cause conflicts.

adding rules to security groups - terraform

We’ll use standalone rules as we’ve already seen inline rules when creating a security group. Before adding any new rules, we will first convert the existing inline rules to standalone rules in the same file.

Converting inline security group rules to standalone rules

  1. Set the ingress and egress attribute to an empty array.
    Note: Terraform doesn’t detect any changes if we completely remove ingress and egress attributes from aws_security_group. This issue can be tracked here. The workaround is to set the ingress and egress attributes to [].
resource "aws_security_group" "web_server_sg_tf" {
 name        = "web-server-sg-tf"
 description = "Allow HTTPS to web server"
 vpc_id      = data.aws_vpc.default.id
 ingress = []
 egress  = []
}
  1. Run the terraform plan command and then the terraform apply command to remove the existing rules before adding any standalone rules to avoid any conflicts.
  2. Add standalone security group rules for HTTP ingress and all egress. Do not forget to remove the inline ingress and egress attributes from the aws_security_group resource to avoid any conflicts.
data "aws_vpc" "default" {
 default = true
}

resource "aws_security_group" "web_server_sg_tf" {
 name        = "web-server-sg-tf"
 description = "Allow HTTPS to web server"
 vpc_id      = data.aws_vpc.default.id
}

resource "aws_security_group_rule" "allow_https" {
 type              = "ingress"
 description       = "HTTPS ingress"
 from_port         = 443
 to_port           = 443
 protocol          = "tcp"
 cidr_blocks       = ["0.0.0.0/0"]
 security_group_id = aws_security_group.web_server_sg_tf.id
}

resource "aws_security_group_rule" "allow_all" {
 type              = "ingress"
 description       = "allow all"
 from_port         = 0
 to_port           = 0
 protocol          = "-1"
 cidr_blocks       = ["0.0.0.0/0"]
 security_group_id = aws_security_group.web_server_sg_tf.id
}
  1. Run terraform plan again. The changes should reflect the two rules being added.
Terraform will perform the following actions:
# aws_security_group_rule.allow_all will be created
 + resource "aws_security_group_rule" "allow_all" {
     + cidr_blocks              = [
         + "0.0.0.0/0",
       ]
     + description              = "allow all"
     + from_port                = 0
     + id                       = (known after apply)
     + protocol                 = "-1"
     + security_group_id        = "sg-03207db609c0bc470"
     + security_group_rule_id   = (known after apply)
     + self                     = false
     + source_security_group_id = (known after apply)
     + to_port                  = 0
     + type                     = "ingress"
   }
# aws_security_group_rule.allow_https will be created
 + resource "aws_security_group_rule" "allow_https" {
     + cidr_blocks              = [
         + "0.0.0.0/0",
       ]
     + description              = "HTTPS ingress"
     + from_port                = 443
     + id                       = (known after apply)
     + protocol                 = "tcp"
     + security_group_id        = "sg-03207db609c0bc470"
     + security_group_rule_id   = (known after apply)
     + self                     = false
     + source_security_group_id = (known after apply)
     + to_port                  = 443
     + type                     = "ingress"
   }
Plan: 2 to add, 0 to change, 0 to destroy.
  1. Finally run the terraform apply command to deploy the changes.
Converting inline security group rules to standalone rules - terraform

Awesome! We successfully added standalone rules to our security group.

Attaching a security group to an EC2 resource

In this tutorial, we will learn how to attach a security group to an EC2 instance.

  1. Add Terraform resource to spin up an EC2 instance.
resource "aws_instance" "web_server" {
 ami                         = "ami-09d56f8956ab235b3"
 instance_type               = "t2.nano"
 key_name                    = "web-server-key"
 associate_public_ip_address = true
 root_block_device {
   volume_type           = "gp2"
   volume_size           = "8"
   delete_on_termination = true
 }
}

Note: We do need to create the web-server-key again as we had previously created it through the console.

  1. Add key vpc_security_group_ids  with the value as [aws_security_group.web_server_sg_tf.id] to attach the previously created security group to this EC2 instance.
resource "aws_instance" "web_server" {
 ami                         = "ami-09d56f8956ab235b3"
 instance_type               = "t2.nano"
 key_name                    = "web-server-key"
 vpc_security_group_ids      = [aws_security_group.web_server_sg_tf.id]
 associate_public_ip_address = true
 root_block_device {
   volume_type           = "gp2"
   volume_size           = "8"
   delete_on_termination = true
 }
}
  1. Run the terraform plan command and review the changes before running the terraform apply command.
  2. Check the AWS console to verify if the security group was attached successfully.
attaching a security group to an EC2 resource - terraform

Awesome! Our security group is attached to our EC2 instance as expected.

How to Use Existing Security Groups

In this tutorial, we will learn how to refer to a security group created outside of terraform using a Terraform data resource.

We will first create a security group outside of Terraform and then add an inbound SSH rule to it using Terraform.

Referring to a single security group

  1. Create a security group by the name security-group-managed-outside-terraform.
{
 "managed-by" = "aws-console"
}
referring to a single security group - terraform
  1. To refer to the security-group-managed-outside-terraform security group, use the aws_security_group data resource and provide the security group id in the main.tf file.

Relevant changes are shown below.

variable "security_group_id" {
 type    = string
 default = "sg-0d7749dea35961abc"
}

data "aws_security_group" "selected" {
 id = var.security_group_id
}
  1. Add an inbound rule to this security group that allows SSH from the default VPC.

Note: We are using an id from the data resource, which is kind of redundant as we already knew the id and used it to fetch the security group. But in real-world scenarios, this can be useful to get other crucial information such as associated VPC id and more.

resource "aws_security_group_rule" "allow_ssh_from_vpc" {
 type              = "ingress"
 description       = "Allow SSH from VPC"
 from_port         = 22
 to_port           = 22
 protocol          = "tcp"
 cidr_blocks       = [data.aws_vpc.default.cidr_block]
 security_group_id = data.aws_security_group.selected.id
  1. Run the terraform plan command. Notice that terraform finds the correct security group and plans to add an inbound rule to it.
Terraform will perform the following actions:

  # aws_security_group_rule.allow_ssh_from_vpc will be created
  + resource "aws_security_group_rule" "allow_ssh_from_vpc" {
      + cidr_blocks              = [
          + "172.31.0.0/16",
        ]
      + description              = "Allow SSH from VPC"
      + from_port                = 22
      + id                       = (known after apply)
      + protocol                 = "tcp"
      + security_group_id        = "sg-0d7749dea35961abc"
      + security_group_rule_id   = (known after apply)
      + self                     = false
      + source_security_group_id = (known after apply)
      + to_port                  = 22
      + type                     = "ingress"
    }

Plan: 1 to add, 0 to change, 0 to destroy.
  1. Run the terraform apply command to deploy the changes.

Referring to multiple security groups

  1. Let us create another security group called security-group-managed-outside-terraform-2 using the AWS console with the tag shown below.
{
 "managed-by" = "aws-console"
}
referring to multiple security groups - terraform
  1. Instead of referring to each of these security groups individually, we can use the aws_security_groups data resource and provide the tag value to refer to all of them at once.

Note: Previously, we used aws_security_group data source to refer to a single security group and now we are using aws_security_group(s) data source to refer to multiple security groups.

data "aws_security_groups" "security_groups_managed_by_aws_console" {
 tags = {
   "managed-by" = "aws-console"
 }
}
  1. Modify the existing inbound SSH rule that we created earlier to add this rule to all the matching security groups. We will use the Terraform for_each meta tag to achieve this. Optionally, add the Terraform output to print all the matching security group ids.
data "aws_security_groups" "security_groups_managed_by_aws_console" {
 tags = {
   "managed-by" = "aws-console"
 }
}

resource "aws_security_group_rule" "allow_ssh_from_vpc" {
 for_each          = toset(data.aws_security_groups.security_groups_managed_by_aws_console.ids)
 type              = "ingress"
 description       = "Allow SSH from VPC"
 from_port         = 22
 to_port           = 22
 protocol          = "tcp"
 cidr_blocks       = [data.aws_vpc.default.cidr_block]
 security_group_id = each.value
}

output "security_group_ids" {
 value = data.aws_security_groups.security_groups_managed_by_aws_console.ids
}
  1. As always, run the terraform plan command and review the changes. The plan should reflect the deletion of the previous rule and the creation of two new rules along with the output security_group_ids.
Terraform will perform the following actions:
# aws_security_group_rule.allow_ssh_from_vpc will be destroyed
 # (because resource uses count or for_each)
 - resource "aws_security_group_rule" "allow_ssh_from_vpc" {
     - cidr_blocks            = [
         - "172.31.0.0/16",
       ] -> null
     - description            = "Allow SSH from VPC" -> null
     - from_port              = 22 -> null
     - id                     = "sgrule-2807208966" -> null
     - protocol               = "tcp" -> null
     - security_group_id      = "sg-0d7749dea35961abc" -> null
     - security_group_rule_id = "sgr-05e047df70ca6e3e2" -> null
     - self                   = false -> null
     - to_port                = 22 -> null
     - type                   = "ingress" -> null
   }
# aws_security_group_rule.allow_ssh_from_vpc["sg-0438324f09abb192e"] will be created
 + resource "aws_security_group_rule" "allow_ssh_from_vpc" {
     + cidr_blocks              = [
         + "172.31.0.0/16",
       ]
     + description              = "Allow SSH from VPC"
     + from_port                = 22
     + id                       = (known after apply)
     + protocol                 = "tcp"
     + security_group_id        = "sg-0438324f09abb192e"
     + security_group_rule_id   = (known after apply)
     + self                     = false
     + source_security_group_id = (known after apply)
     + to_port                  = 22
     + type                     = "ingress"
   }
# aws_security_group_rule.allow_ssh_from_vpc["sg-0d7749dea35961abc"] will be created
 + resource "aws_security_group_rule" "allow_ssh_from_vpc" {
     + cidr_blocks              = [
         + "172.31.0.0/16",
       ]
     + description              = "Allow SSH from VPC"
     + from_port                = 22
     + id                       = (known after apply)
     + protocol                 = "tcp"
     + security_group_id        = "sg-0d7749dea35961abc"
     + security_group_rule_id   = (known after apply)
     + self                     = false
     + source_security_group_id = (known after apply)
     + to_port                  = 22
     + type                     = "ingress"
   }
Plan: 2 to add, 0 to change, 1 to destroy.
Changes to Outputs:
 + security_group_ids = [
     + "sg-0047037cef35cecd3",
     + "sg-0d7749dea35961abc",
   ]
  1. Finally, run the terraform apply command to deploy the changes to all relevant security groups.

Next, we will learn to import security groups existing outside terraform into terraform.

Importing existing security groups under terraform

When migrating an existing resource to terraform, it is not always feasible to delete and recreate it. In such cases, we can import resources directly into Terraform. Let us look at how we can easily bring existing security groups from outside of Terraform into Terraform.

We will import one of the resources we created earlier into Terraform in this tutorial. To learn more, see our Importing Existing Infrastructure into Terraform tutorial.

  1. Declare the resource you want to import in the main.tf file. Add as many details to it as possible.
resource "aws_security_group" "imported_sg_tf" {
 name        = "security-group-managed-outside-terraform-2"
 description = "Security group managed outside terraform"
 vpc_id      = data.aws_vpc.default.id
 tags = {
   "managed-by" = "aws-console"
 }
}
  1. Run the below command with an id of the security group you want to import.
terraform import aws_security_group.imported_sg_tf sg-0047037cef35cecd3
# Replace the security group id before running command


terraform import security group
  1. Run the terraform plan command to ensure that no changes are reflected.
terraform import security group - terraform plan

This signifies that the resource was imported successfully with no conflicts 🎉

At this point, we’ve learned about how to create and manage security groups using both the console and Terraform. Let’s take a look at some popular applications and how they can help improve the security posture of a resource/application.

Applications of Security Groups

Security groups are a key part of the security of resources on AWS. There are multiple use cases where they are required, such as:

  • Managing HTTPS(443) or HTTP(80) traffic to a web server.
  • Configuring access to RDS instances. (Learn how to create an AWS RDS instance using Terraform.)
  • Permitting traffic only from specific address ranges to the corporate network.
  • Limiting SSH access to compute instances.
  • Managing traffic to and from Lambda functions and more

Their usage is not limited to the above examples but extends to NAT Gateways, ECS, EKS, Code Build, and more.

It is already evident that security groups are crucial for network security. As mentioned earlier, security groups are one of two security features available to control traffic in your VPC. NACLs are the other type. To better configure network security, it is important to understand how security groups are different from NACLs and when to use what.

Security groups vs NACL

Before we get into how security groups differ from NACLs, let us quickly understand what NACLs are.

Network access control list (NACL)

NACLs, like security groups, are firewalls that allow you to control incoming and outgoing traffic. The main distinction between NACLs and security groups is that NACLs operate at the subnet level, whereas security groups operate at the resource level.

They can be used as a secondary control to define high-level guard rails for filtering traffic at the subnet level.

NACLs can help to improve a VPC’s security posture as they filter traffic regardless of whether a security group is associated with resources or not.

Network access control list

Security groups vs NACL

Although both security groups and NACLs are used to improve a VPC’s security posture, they have significant differences. The main points are as follows:

Security groups NACLs
Work at the instance level                         Work at the subnet level
Only accept “Allow” rules Accept both “Allow” and “Deny” rules
Stateful Stateless
The primary defense

 

A secondary defense and considered optional

 

Rules do not have a priority Rules have priority based on which they are evaluated           

Security groups and NACLs can be used in tandem to implement the defense-in-depth strategy. NACLs supplement security groups and serve as an additional layer of protection.

This article would be incomplete without covering the best practices and the basics of compliance of security groups in AWS. Let us jump into it right away.

Security Groups and Compliance

Network security is one of the most important aspects to take care of to improve the security posture. This becomes more difficult as the number of resources and accounts in an organization grows.

With many AWS accounts within an organization, how do we know if:

  • Any of the security groups are over-permissive?
  • Are there redundant or unused security groups?
  • The security groups are compliant?
  • Someone changes something with the existing security groups to make them less secure?

Furthermore, how do we make sure we are always compliant with the standard security benchmarks?

This is where AWS Firewall Manager and Security Hub come into the picture.

AWS Firewall Manager for Security Groups

AWS firewall manager solves all the above problems for us. It can track, audit, and even remediate issues with your security groups across all accounts.

It provides centralized visibility across all accounts to continuously monitor and manage violations and non-compliance.

The below picture depicts how the AWS Firewall manager automatically tracks non-compliance of the security groups.

AWS Firewall Manager for Security Groups

AWS Firewall accomplishes this through the use of security group policies. These policies act as guard rails for creating new security groups or remediating issues with existing ones.

There are three types of security group policies:

  • Common security groups
  • Auditing and enforcement of security group rules
  • Auditing and cleanup of unused and redundant security groups.
security groups policies
  1. Common security groups policy help us to provision common or baseline security groups required in all accounts. For example, allowing SSH from only the corporate IP addresses.
  2. Auditing of security groups assists us identity any security groups that do not adhere to the standard that we have created. These can be security groups with overly permissive or risky rules. It is also possible to automatically remediate non-compliant security groups.
  3. An audit usage policy assists in detecting and removing unused security groups. It also helps in detecting and merging redundant security groups.

AWS Firewall Manager can send issues and alerts to AWS Security Hub for centralized compliance management.

AWS Security Hub for security groups

AWS Security Hub is a service that performs security checks. It aggregates all security alerts and issues in one place and enables us to visualize an organization’s security posture. It supports standards like:

These standards include many security best practices for security groups, such as:

  • CIS AWS Foundations 3.10: Ensure a log metric filter and alarm exist for security group changes
  • PCI.EC2.5: Security groups should not allow ingress from 0.0.0.0/0 to port 22
  • CIS AWS Foundations 4.2: Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389
  • PCI.EC2.2: VPC default security group should prohibit inbound and outbound traffic

and many more.

Any violations are automatically detected and aggregated. It enables us to configure automatic remediation to ensure that our security groups remain secure and compliant at all times.

Key Points

Security groups are one of the most important security features for network security. They are simple yet powerful and thus find their uses across a wide variety of AWS services wherever networks are involved. When used correctly, they can significantly reduce attack vectors to network resources and improve the overall security posture.

Yet, it is crucial to remember that they are not a silver bullet to network security. It is just as important to have other defense mechanisms like NACLs, AWS Security Hub, AWS Firewall, etc, in place to have a more effective line of defense.

Note: New versions of Terraform will be placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that will expand on Terraform’s existing concepts and offerings. It is a viable alternative to HashiCorp’s Terraform, being forked from Terraform version 1.5.6. OpenTofu retained all the features and functionalities that had made Terraform popular among developers while also introducing improvements and enhancements. OpenTofu works with your existing Terraform state file, so you won’t have any issues when you are migrating to it.

Manage Terraform Better with Spacelift

Build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource visualization and many more.

Start free trial
Terraform CLI Commands Cheatsheet

Initialize/ plan/ apply your IaC, manage modules, state, and more.

Share your data and download the cheatsheet