An Amazon AWS Security Group is a virtual firewall for your EC2 instances that controls inbound and outbound traffic at the instance level. They are a fundamental building block for securing your cloud infrastructure. By creating rules, you can define exactly what traffic is allowed to reach your instances, such as allowing web traffic on port 80, while blocking everything else. Their stateful nature simplifies rule creation, a key concept we will explore in detail.
Key Takeaways
- Security Groups are stateful firewalls. If you allow inbound traffic, the corresponding outbound return traffic is automatically allowed, regardless of outbound rules.
- By default, a new security group denies all inbound traffic and allows all outbound traffic.
- Rules can only allow traffic. There are no “deny” rules. Traffic is denied if no rule explicitly allows it.
- Security Groups are associated with network interfaces on an EC2 instance, not the subnet.
- Rule sources can be an IP address (CIDR), another security group, or a prefix list, enabling dynamic and secure communication between application tiers.
Security Groups Explained
Think of a Security Group as a bouncer standing at the door of your EC2 instance. They have a list of approved guests (rules). If someone (traffic) tries to enter and isn’t on the list, they are turned away. Let’s do a deep dive into how they work, focusing on the concepts most important to network engineers.
Stateful vs. Stateless: The Key Difference
The most important characteristic of a Security Group is that it is stateful. This is a concept familiar to anyone who has worked with a firewall.
When you allow inbound traffic on a certain port (e.g., TCP port 80 for a web server), the Security Group tracks that connection. When the web server responds to the client, the Security Group recognizes this as return traffic for an established connection and automatically allows it to exit, even if you have no outbound rules that would otherwise permit it.
This is in direct contrast to Network ACLs (NACLs), which are stateless firewalls that operate at the subnet level. With a stateless firewall, you must create explicit rules for both inbound and outbound traffic. For a web server, you’d need an inbound rule for port 80 and a corresponding outbound rule for the high-numbered ephemeral ports (1024-65535) used for the return traffic.
Crafting Security Group Rules
When creating a Security Group, we start with a clean slate: no inbound rules (everything is denied) and one outbound rule that allows all traffic. We then add allow rules to permit the traffic we need. A rule consists of:
- Type: A common protocol like SSH, HTTP, HTTPS, or a custom one.
- Protocol: TCP, UDP, ICMP, etc.
- Port Range: The port or range of ports (e.g., 80, 443, 3306).
- Source (for inbound rules) / Destination (for outbound rules): This is where it gets interesting. You can specify:
- A CIDR block (e.g.,
192.0.2.24/32for a single IP, or0.0.0.0/0for any IP). - Another Security Group ID. This is an incredibly powerful feature.
- A CIDR block (e.g.,
Practical Example: Web and Database Tiers
Let’s design the security for a classic two-tier application with a public-facing web server and a private database server. We only want the web server to be able to talk to the database.
1. Create the Database Security Group (`db-sg`)
First, we create a security group for our database instance. We want to allow MySQL traffic (port 3306), but only from our future web servers.
In the AWS Console, create a new security group named `db-sg`. For the inbound rule:
- Type: MYSQL/Aurora
- Protocol: TCP
- Port Range: 3306
- Source: We will come back and fill this in with our web server’s security group ID. For now, we can create it without a source.
2. Create the Web Server Security Group (`web-sg`)
Now, create a security group for the web servers. This needs to allow public web traffic and allow us to manage it via SSH.
- Rule 1 (Web Traffic):
- Type: HTTP
- Port: 80
- Source: Anywhere (
0.0.0.0/0)
- Rule 2 (Secure Web Traffic):
- Type: HTTPS
- Port: 443
- Source: Anywhere (
0.0.0.0/0)
- Rule 3 (Management):
- Type: SSH
- Port: 22
- Source: My IP (AWS will auto-populate your public IP address)
3. Connecting the Tiers
Now, we go back to our `db-sg`. Edit its inbound rules and add a new one. For the source, instead of typing an IP, start typing `sg-` and select the ID of the `web-sg`. Your `db-sg` inbound rule should now be:
# db-sg Inbound Rules
# Type Protocol Port Source
#-------------------------------------------
# MYSQL/Aurora TCP 3306 sg-xxxxxxxx (web-sg)
4. Verification
Now, when we launch an EC2 instance and attach `web-sg` to it, it can receive traffic from the internet on ports 80 and 443. When we launch our database instance and attach `db-sg`, it will only accept traffic on port 3306 if it originates from an instance that has the `web-sg` attached. This is far more secure and dynamic than hardcoding IP addresses. If we scale our web tier to 100 instances, they can all automatically talk to the database because they all use the same security group.
Conclusion
In this lesson, we demystified AWS Security Groups. We learned that they are stateful, instance-level firewalls that default to denying all inbound traffic. We saw how their “allow-only” rules and, most importantly, their ability to reference other security groups as a source, enable us to build secure, scalable, and multi-tiered applications in the cloud. Mastering security groups is not just recommended; it’s a mandatory skill for any engineer working with AWS and a frequent topic on all AWS certification exams.