AWS with Terraform Tutorial: AWS Security Groups (9)

How to Create, and Manage AWS Security Groups with Terraform

How to configure and use the Terraform aws_security_group and aws_security_group_rule resource blocks to create and manage AWS Security Groups and secure the infrastructure.

Welcome to our tutorial series where we dive into cloud infrastructure deployment using Terraform or OpenTofu on AWS. In this series, the fundamentals are shown, guiding you through the process of minimizing resource usage and simplifying the deployment complexities associated with cloud infrastructure. This tutorial series is a work in progress.

This comprehensive OpenTofu and Terraform tutorial guides you step-by-step through creating infrastructure in AWS using Terraform.

Terraform Basics, AWS Basics, Terraform AWS Provider, AWS VPC, AWS Subnets, AWS Internet Gateway, AWS NAT Gateway, AWS Routing Tables, AWS Security Groups, AWS Key Pairs, AWS AMIs, AWS EC2 Instances, AWS RDS, AWS Route 53 (DNS), AWS Auto Scaling, AWS Load Balancers, Terraform AWS & Ansible, Terraform Modules, Terraform Backends, Terraform Tools, Terraform CI/CD.

Infrastructure as Code (IaC) helps maintain consistency, enables version control, enhances collaboration among teams, allows for easier replication of environments, streamlines the deployment and management of infrastructure boosting efficiency, and reducing errors in managing complex systems.

How to start building AWS infrastructure with Terraform: Security Groups

  1. Prerequisites

    Read previous sections of the tutorial: AWS with Terraform Tutorial

  2. AWS Security Groups

    Security Groups are composed of Security Rules that define the inbound or outbound flows. In AWS, Security Groups define what is authorized, by default everything else is denied.

  3. AWS Connectivity Diagrams

    A diagram with the services, listening ports, and intended connections helps design a secure infrastructure.

  4. Terraform AWS Configuration Plan Definition

    Previous sections of the Tutorial have covered basic information about Terraform, AWS Cloud, the Terraform AWS Provider, VPC, Subnets, Internet Gateway, NAT Gateway, and Routing Tables. In this section, the Security Groups needed to allow traffic are presented.

  5. How to create an AWS Security Group with Terraform

    An AWS An AWS Security Group acts as a virtual firewall for AWS instances and services controlling inbound and outbound traffic. It is a set of rules that filter traffic based on protocols, ports, and origins or destinations.

  6. Run the Terraform Plan

    Plan, and apply the Terraform plan to create the Security Groups in AWS.

  7. Security Groups Cost

    There is no cost for creating or having Security Groups in AWS.

  8. Common Questions About AWS Security Groups

    Can the source be an IP address for instance inbound? How does Security Group differ from Network ACL? What's the default rule for a new Security Group? ...

  9. Next Steps

    Other tutorials for creating infrastructure in AWS using Terraform.

Prerequisites

  • Read previous sections of the tutorial:

AWS Security Groups

An AWS Security Group acts as a virtual firewall for AWS instances and services controlling inbound and outbound traffic. It is a set of rules that filter traffic based on protocols, ports, and origins or destinations.

Security Groups are composed of Security Rules that define the inbound or outbound flows. In AWS, Security Groups define what is authorized, by default everything else is denied.

The diagram shows the elements of a Security Group:

ITWL Tutorials AWS Terraform Essentials Security Groups Rules

Ingress or Inbound Rules

Ingress Rules, also called Inbound Rules apply to traffic that enters the instance, e.g. traffic generated on the Internet that reaches an instance (instance being the destination).

Components of an Inbound or Ingress Security Rule are:

Type

All types of traffic, TCP, UDP, or ICMP (e.g. ping)

Port or Port Range

The destination port can be a single port or a range. A single port is specified with its number (e.g. 80) and a range with a start port number, a dash, and the end port number (e.g. 1024-1040). The port number is only required for TCP and UDP protocols.

Source

The origin is the instance or network generating the traffic, it can be specified in many different ways:

  • IPv4 CIDR notation (e.g. 75.2.98.97/32)
  • IPv6 CIDR notation (e.g. 2001:db6::/32)
  • IPv4 Anywhere (0.0.0.0/0)
  • IPv6 Anywhere (::/0)
  • An AWS Prefix (a set of one or more CIDR blocks). See Group CIDR blocks using managed prefix lists.
  • A Security Group: This is the recommended way to specify inter-VPC instance sources. The source is the instance that has a group with this name attached.
Destination

Specifies the resource the incoming network traffic is trying to reach. The destination in an inbound rule is not specified as it is derived from the instances that have the Security Group attached. E.g. If the security group is attached to instance-web-server-01 and instance-web-server-02, then the destination becomes any of those instances.

Description

A text explaining intended use that acts as documentation

Tags

A list of tags and values classifying the rule.

Egress or Outbound Rules

Egress Rules, also called Outbound Rules apply to traffic that leaves the instance, e.g. traffic generated in the instance that is sent to another instance or destination (e.g. from an Instance to the Internet).

When you create a new Security Group in a VPC, AWS sets up an allow all egress rule by default. However, when using Terraform, this default rule is removed.

Components of an Egress or Outbound Security Rule are:

Type

All types of traffic, TCP, UDP, or ICMP (e.g. ping)

Port or Port Range

The destination port can be a single port or a range. A single port is specified with its number (e.g. 80) and a range with a start port number, a dash, and the end port number (e.g. 1024-1040). The port number is only required for TCP and UDP protocols.

Source

Specifies the resource that is generating the outgoing network traffic. The source in an outbound rule is not specified as it is derived from the instances that have the Security Group attached. E.g. If the security group is attached to instance-web-server-01, then the source becomes this instance (eg. this instance is the source for traffic going to a database instance in a private subnet).

Destination

The destination is the instance or network where the traffic is going, it can be specified in many different ways:

  • IPv4 CIDR notation (e.g. 75.2.98.97/32)
  • IPv6 CIDR notation (e.g. 2001:db6::/32)
  • IPv4 Anywhere (0.0.0.0/0)
  • IPv6 Anywhere (::/0)
  • An AWS Prefix (a set of one or more CIDR blocks). See Group CIDR blocks using managed prefix lists.
  • A Security Group: This is the recommended way to specify inter-VPC instance sources. The source is the instance that has a group with this name attached.
Description

A text explaining intended use that acts as documentation

Tags

A list of tags and values classifying the rule.

Connectivity Diagrams

Security should be taken as a priority when designing any Infrastructure. A secure instance will have by default all then incoming traffic denied and only the needed ports open and if possible only to traffic originating from known sources. E.g. A database server that stores data for a web application should have all inbound traffic denied except the one originating from the application that uses the data (a web server probably).

A diagram with the services, listening ports, and intended connections helps design a secure infrastructure.

The diagram shows two instances that will be added in the next sections and their connectivity requirements:

ITWL Tutorials AWS Terraform Essentials Security Groups Design 2 1

EC2 Instance: ditwl-ec-front-end-001

A front-end instance, located in the ditwl-sn-za-pro-pub-00 Public Subnet. Instances in public subnets are usually exposed to the Internet, this one will expose port 80 and run an HTTP server.

Connectivity requirements:

  • Outbound access (from the instance) to the Internet: the instance should be able to access the Internet to download updates.
  • Inbound access (to the instance) from the Internet to the Instance TCP port 80.
  • Outbound access (from the instance) to the TCP port 8080 on the back-end server ditwl-ec-back-end-123 instance.

EC2 Instance: ditwl-ec-back-end-123

A back-end instance, located in the ditwl-sn-za-pro-pub-00 Private Subnet. Instances in private subnets are not exposed to the Internet, this one will expose port 8080 and run an HTTP server (e.g. an API).

Connectivity requirements:

  • Outbound access (from the instance) to the Internet: the instance should be able to access the Internet to download updates. It will use the NAT Gateway, although it doesn't have an impact on the Security Rules.
  • Inbound access from the instance ditwl-ec-front-end-001 to the TCP port 8080.

Security Groups Needed

To have a secure infrastructure, each group of common services (eg. cluster of web servers running the same application) requires a specific security group, additionally a security group with common rules for all the instances can be added to open ssh and observability access from selected sources.

ITWL Tutorials AWS Terraform Essentials Security Groups
Security Group ditwl-sg-base-ec2

This is a security group with common rules that should be applied to all instances. It allows inbound connectivity to port TCP 22 from the Internet and also ICMP.

See How to programmatically use your public Internet IP address in Terraform? for a better approach.

Ingress Security Rule ditwl-sr-internet-to-ec2-ssh

Allows inbound connectivity to port TCP 22 from the Internet. Allowing SSH from any address is a security risk as the instances could be compromised. The recommended practice is to limit SSH access to a set of known IP addresses corresponding to the management network or use EC2 Instance Connect with private IP addresses.

Ingress ditwl-sr-internet-to-ec2-icmp

Allows inbound ICMP from the Internet, those again is not a recommended practice and should be limited to a set of known IP addresses corresponding to the management network.

ditwl-sr-all-outbund

Allows all outbound connectivity from the instance, including access to the Internet.

Security Group ditwl-sg-front-end

This security group defined the access rules for the Front End Instance.

Ingress ditwl-sr-internet-to-front-end-http

Allow access from the Internet to TCP port 80 (for a web server).

Security Group ditwl-sg-back-end

This security group defined the access rules for the Back-End Instance, allowing access only from the Front-End instance.

Ingress ditwl-sr-front-end-to-api

Allow access from instances having the ditwl-sg-front-end security group assigned to TCP port 8080 (for a web server offering an API).

How to create an AWS Security Group with Terraform

Previous sections of this AWS with Terraform guide have covered basic information about Terraform and AWS and have configured and used the AWS Terraform provider to create a VPC, four subnets, one Internet Gateway, two NAT Gateways, and three Routing Tables.

It is time to create Security Groups that will allow traffic between different resources and to the Internet.

Keep adding Terraform blocks to the terraform-aws-tutorial.tf created in previous sections.

Terraform Code for Security Groups

Security Group creation is done with aws_security_group and aws_security_group_rule Terraform Blocks.

Security Groups need to be assigned to Instances using the Instance creation block aws_instance property vpc_security_group_ids. See the EC2 Instance creation section for the assignment.

Add the following block to the file terraform-aws-tutorial.tf.

For Security Group ditwl-sg-base-ec2:

# Create a "base" Security Group for EC2 instances
resource "aws_security_group" "ditwl-sg-base-ec2" {
  name        = "ditwl-sg-base-ec2"
  vpc_id      = aws_vpc.ditlw-vpc.id
  description = "Base security Group for EC2 instances"
}

# DANGEROUS!!
# Allow access from the Internet to port 22 (SSH) in the Public EC2 instances
resource "aws_security_group_rule" "ditwl-sr-internet-to-ec2-ssh" {
  security_group_id = aws_security_group.ditwl-sg-base-ec2.id
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"] # Internet
  description       = "Allow access from the Internet to port 22 (SSH)"
}

# Allow access from the Internet for ICMP protocol (e.g. ping) to the EC2 instances
resource "aws_security_group_rule" "ditwl-sr-internet-to-ec2-icmp" {
  security_group_id = aws_security_group.ditwl-sg-base-ec2.id
  type              = "ingress"
  from_port         = -1
  to_port           = -1
  protocol          = "icmp"
  cidr_blocks       = ["0.0.0.0/0"] # Internet
  description       = "Allow access from the Internet for ICMP protocol"
}

# Allow all outbound traffic to the Internet
resource "aws_security_group_rule" "ditwl-sr-all-outbund" {
  security_group_id = aws_security_group.ditwl-sg-base-ec2.id
  type              = "egress"
  from_port         = "0"
  to_port           = "0"
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  description       = "Allow all outbound traffic to Internet"
}

For Security Group ditwl-sg-front-end:

# Create a Security Group for the Front end Server
resource "aws_security_group" "ditwl-sg-front-end" {
  name        = "ditwl-sg-front-end"
  vpc_id      = aws_vpc.ditlw-vpc.id
  description = "Front end Server Security"
}

# Allow access from the Internet to port 80 HTTP in the EC2 instances
resource "aws_security_group_rule" "ditwl-sr-internet-to-front-end-http" {
  security_group_id = aws_security_group.ditwl-sg-front-end.id
  type              = "ingress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"] # Internet
  description       = "Access from the Internet to port 80 in the EC2 instances"
}

For Security Group ditwl-sg-back-end:

# Create a Security Group for the Back-end Server
resource "aws_security_group" "ditwl-sg-back-end" {
  name        = "ditwl-sg-back-end"
  vpc_id      = aws_vpc.ditlw-vpc.id
  description = "Back-end Server Security"
}

# Allow access from the front-end to port 8080 in the back-end API
resource "aws_security_group_rule" "ditwl-sr-front-end-to-api" {
  security_group_id        = aws_security_group.ditwl-sg-back-end.id
  type                     = "ingress"
  from_port                = 8080
  to_port                  = 8080
  protocol                 = "tcp"
  source_security_group_id = aws_security_group.ditwl-sg-front-end.id
  description              = "Allow access from the front-end to port 8080 in the back-end API"
}

Run the Terraform Plan

Open a command line shell at the same location where the terraform-aws-tutorial.tf file is located, and, run the Terraform or OpenTofu plan, and apply the commands.

Plan using OpenTofu

Run tofu plan to generate and review the execution plan. Check each line and value to make sure that it corresponds to the desired change.

Terraform will refresh the state comparing it with the Cloud resources and produce a plan for the resources that need to be created, updated, or destroyed.

In the past section of the tutorial, some resources were commented out to reduce the infrastructure cost during development, as the security Groups don't have any dependency yet with the commented code, there is no need to uncomment.

Run the Terraform plan:

Apply the changes using OpenTofu

Run tofu apply to generate and apply the execution plan. OpenTofu will generate a new plan and ask for confirmation before applying the changes. Review again the changes and answer yes or no to apply the changes in AWS.

Review the result, it should be 12 (resource) added, 0 changed, 0 destroyed.

Security Groups Cost

There is no cost for creating or having Security Groups in AWS.

Common Questions About AWS Security Groups

Can the source be an IP address for instance inbound?

It can be, although it is not recommended as the common practice is to use DHCP for private IP address assignment. If the instance IP address changes after a reboot then all security rules will need to be updated and if the old IP address gets assigned to another instance it can create a security risk.

How does Security Group differ from Network ACL?

SG is stateful, and operates at the instance level; NACL is stateless and works at the subnet level.

What's the default rule for a new Security Group?

All inbound traffic is denied; outbound is allowed.

Can I assign multiple Security Groups to an instance?

Yes, you can associate up to five SGs with an instance.

Do Security Groups support deny rules?

No, SGs are stateful and allow rules but no explicit deny; if a rule isn't allowed, it's denied.

Next Steps

This tutorial series is a work in progress and will have these sections:

Terraform Basics, AWS Basics, Terraform AWS Provider, AWS VPC, AWS Subnets, AWS Internet Gateway, AWS NAT Gateway, AWS Routing Tables, AWS Security Groups, AWS Key Pairs, AWS AMIs, AWS EC2 Instances, AWS RDS, AWS Route 53 (DNS), AWS Auto Scaling, AWS Load Balancers, Terraform AWS & Ansible, Terraform Modules, Terraform Backends, Terraform Tools, Terraform CI/CD.

AWS with Terraform: The Essential Guide: Sections

Leave a Reply

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


Related Cloud Tutorials

Securing your Infrastructure: Encrypting Terraform State Files with OpenTofu
Using the Terraform aws_route53_delegation_set, aws_route53_zone, and aws_route53_record resource blocks to configure DNS in AWS.
Using the Terraform aws_db_instance resource block to configure, launch, and secure RDS instances.
How to use the Terraform aws_instance resource block to configure, launch, and secure EC2 instances.
How to configure and use the Terraform aws_ami data source block to find and use AWS AMIs as templates (root volume snapshot with operating system and applications) for EC2 instances.
Javier Ruiz Cloud and SaaS Expert

Javier Ruiz

IT Wonder Lab tutorials are based on the diverse experience of Javier Ruiz, who founded and bootstrapped a SaaS company in the energy sector. His company, later acquired by a NASDAQ traded company, managed over €2 billion per year of electricity for prominent energy producers across Europe and America. Javier has over 25 years of experience in building and managing IT companies, developing cloud infrastructure, leading cross-functional teams, and transitioning his own company from on-premises, consulting, and custom software development to a successful SaaS model that scaled globally.

Are you looking for cloud automation best practices tailored to your company?

linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram