Security Layer: Security Group Chaining

Designing the Security Boundary

Network isolation via subnets and route tables establishes macro-level boundaries. Security groups enforce micro-level access control at the resource level. In a multi-tier architecture, the goal is to ensure that each tier can only be reached by the tier directly above it — and only on the specific port required.

You will create three security groups and wire them so that membership in an upstream group is the only valid source for the downstream group.

Creating the Security Groups

Navigate to VPC > Security Groups > Create security group.

Load Balancer Security Group (sg-lb):

  • VPC: lab-vpc
  • Inbound: TCP 80 from 0.0.0.0/0, TCP 443 from 0.0.0.0/0
  • Outbound: default (all traffic allowed) — this allows the LB to forward to the app tier

The load balancer is the only tier with public inbound access. Opening only 80 and 443 means even if an attacker scans your IP, no other ports are reachable.

Application Tier Security Group (sg-app):

  • VPC: lab-vpc
  • Inbound: TCP 8080 (or your app port) from source security group sg-lb

Do not enter an IP range. Enter the security group ID of sg-lb. This is the chaining pattern. Only resources that are members of sg-lb can send traffic to this tier on port 8080. When your Auto Scaling group replaces load balancer instances, new instances automatically carry group membership and are immediately permitted. No rule updates required.

Database Tier Security Group (sg-db):

  • VPC: lab-vpc
  • Inbound: TCP 5432 (PostgreSQL) or TCP 3306 (MySQL) from source security group sg-app

Same principle: only application-tier resources can reach the database. This prevents a scenario where a compromised load balancer could directly query the database — it can only reach the app tier, which enforces its own validation before touching the DB.

Validating the Chain

After creating the security groups, review the inbound rules for sg-app and sg-db. The source column should show security group IDs (e.g., sg-0abc1234...), not IP ranges.

What you should see in the console: For sg-app, the inbound rule source shows the security group ID of sg-lb. For sg-db, the inbound rule source shows the security group ID of sg-app. No IP-based rules exist for inter-tier communication.

Production hardening note: Remove the default outbound “all traffic” rule from sg-app and sg-db and replace it with explicit egress rules. For sg-app, allow TCP 5432 (or 3306) outbound to sg-db, and allow TCP 443 outbound to 0.0.0.0/0 for external API calls. For sg-db, allow no outbound by default unless you have a specific requirement. Least-privilege egress rules limit blast radius if an instance is compromised.

Network ACLs: When to Use Them

Network ACLs (NACLs) are stateless, subnet-level firewalls. Unlike security groups, they evaluate both inbound and outbound rules independently and process rules in order by rule number. Because security groups already provide strong per-resource control, NACLs are most useful as a secondary line of defense for subnet-level blocking — for example, blocking a known malicious IP range at the subnet boundary.

For this lab, the default NACLs (allow all) are acceptable. In production, adding a NACL rule to block traffic from the internet directly to private subnet CIDRs (even though routing already prevents it) adds a defense-in-depth layer. Do not rely on NACLs as your primary access control mechanism — the stateless nature makes them error-prone for application-level traffic rules.

In this section, I confirmed:

0 of 5 completed

Choose your language

Select your preferred language for the site