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.
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
Read previous sections of the tutorial: AWS with Terraform Tutorial
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.
A diagram with the services, listening ports, and intended connections helps design a secure infrastructure.
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.
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.
Plan, and apply the Terraform plan to create the Security Groups in AWS.
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? How does Security Group differ from Network ACL? What's the default rule for a new Security Group? ...
Other tutorials for creating infrastructure in AWS using Terraform.
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:
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:
All types of traffic, TCP, UDP, or ICMP (e.g. ping)
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.
The origin is the instance or network generating the traffic, it can be specified in many different ways:
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.
A text explaining intended use that acts as documentation
A list of tags and values classifying the rule.
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:
All types of traffic, TCP, UDP, or ICMP (e.g. ping)
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.
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).
The destination is the instance or network where the traffic is going, it can be specified in many different ways:
A text explaining intended use that acts as documentation
A list of tags and values classifying the rule.
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:
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:
ditwl-ec-back-end-123
instance.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:
ditwl-ec-front-end-001
to the TCP port 8080.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.
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.
The recommended security practice is to limit SSH and ICMP access to a set of known IP addresses corresponding to the management network.
See How to programmatically use your public Internet IP address in Terraform? for a better approach.
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.
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.
Allows all outbound connectivity from the instance, including access to the Internet.
This security group defined the access rules for the Front End Instance.
Allow access from the Internet to TCP port 80 (for a web server).
This security group defined the access rules for the Back-End Instance, allowing access only from the Front-End instance.
Allow access from instances having the ditwl-sg-front-end
security group assigned to TCP port 8080 (for a web server offering an API).
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.
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" }
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.
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:
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
.
There is no cost for creating or having Security Groups in AWS.
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.
SG is stateful, and operates at the instance level; NACL is stateless and works at the subnet level.
All inbound traffic is denied; outbound is allowed.
Yes, you can associate up to five SGs with an instance.
No, SGs are stateful and allow rules but no explicit deny; if a rule isn't allowed, it's denied.
This tutorial series is a work in progress and will have these sections:
AWS with Terraform: The Essential Guide: Sections
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?