Security Groups
Security groups are stateful, allow-only firewalls attached to network interfaces. Design a three-tier chain where each tier only accepts traffic from the security group in front of it, and see why SG references beat IP ranges.
🎯 What you'll learn
- What security groups are: stateful, allow-only, per ENI
- Inbound/outbound rules and default behaviour
- CIDR sources vs security-group references
- Tiered designs, SGs vs NACLs, connection tracking
📚 Before you start
1What a Security Group Is
A security group (SG) is a stateful virtual firewall attached to an elastic network interface (ENI) — so to EC2 instances, ECS tasks (awsvpc), RDS instances, Lambda functions in a VPC, load balancers, VPC endpoints. It decides which traffic may reach (ingress) and leave (egress) that interface.
┌──────────── sg-app ────────────┐
alb (sg-alb) ──► │ ingress: tcp 3000 from sg-alb │──► rds (sg-db: tcp 5432 from sg-app)
│ egress: all (default) │
└─────────────────────────────────┘2The Rules of the Game
- Allow rules only — there are no deny rules. Anything not allowed is denied.
- Stateful: if inbound traffic is allowed, the response is automatically allowed out (and vice versa). You never write rules for ephemeral return ports (unlike NACLs —
02-vpc_subnets_route_tables§6). - All rules are evaluated together (no order); the most permissive match wins.
- Default SG for a new group: no inbound, all outbound allowed.
- An ENI can have up to 5 SGs (adjustable); rules from all of them are unioned.
- Changes apply immediately to existing and new connections' evaluation (tracked connections keep flowing).
3Sources: CIDR vs Security Group References
# CIDR source — anyone in that address range
aws ec2 authorize-security-group-ingress --group-id sg-alb --protocol tcp --port 443 --cidr 0.0.0.0/0
# SG reference — any ENI that has sg-alb attached, whatever its IP
aws ec2 authorize-security-group-ingress --group-id sg-app --protocol tcp --port 3000 --source-group sg-alb
# managed prefix list — e.g. CloudFront's origin-facing IP ranges
aws ec2 authorize-security-group-ingress --group-id sg-alb \
--ip-permissions 'IpProtocol=tcp,FromPort=443,ToPort=443,PrefixListIds=[{PrefixListId=pl-xxxxxxxx}]'Referencing security groups is the key design tool: rules describe roles ("the app tier may talk to the DB tier") instead of IP addresses, so autoscaling, redeploys and IP changes never require rule updates.
4A Tiered Design
| SG | Ingress | Egress |
|---|---|---|
sg-alb | 443 from 0.0.0.0/0 (or CloudFront prefix list) | 3000 to sg-app |
sg-app | 3000 from sg-alb | 5432 to sg-db, 6379 to sg-cache, 443 to the internet (via NAT) for third-party APIs |
sg-db | 5432 from sg-app (and sg-migrations) | none needed (stateful replies) |
sg-cache | 6379 from sg-app | none |
sg-bastion → replace with SSM Session Manager: no inbound 22 at all |
Tightening egress (instead of the default allow-all) limits what a compromised instance can reach — data exfiltration and command-and-control traffic.
5Security Groups vs NACLs
| Security group | Network ACL | |
|---|---|---|
| attached to | ENI (instance-level) | subnet |
| state | stateful | stateless (return traffic needs explicit rules) |
| rules | allow only | allow and deny, numbered, evaluated in order |
| typical use | primary, fine-grained control | coarse subnet guardrails, explicit denies (block an IP range) |
Use SGs for nearly everything; NACLs as an extra layer or for explicit deny lists.
Under the HoodConnection Tracking▾
Statefulness is implemented with connection tracking on the host's virtual network: when an allowed flow starts, the 5-tuple (protocol, src IP/port, dst IP/port) is recorded, and packets matching a tracked flow are allowed regardless of rules. Consequences:
- Removing a rule doesn't cut an established tracked connection immediately — existing flows continue until they end or time out (unless the rule was an "untracked" all-open rule, a subtle edge case). To kill a compromised session, also use NACLs or stop the instance.
- Tracked connections consume per-ENI conntrack capacity; very high connection rates (e.g. a UDP-heavy service) can hit allowance limits, visible as
conntrack_allowance_exceededin ENA metrics. - Some flows are untracked when rules allow all traffic both ways (
0.0.0.0/0all protocols in and out), which is why tightening rules can surprisingly increase conntrack usage.
⚠️ Common Pitfalls
0.0.0.0/0on SSH/RDP/database ports.- CIDR rules for internal tiers instead of SG references — break on IP changes, too broad.
- Allow-all egress everywhere — no exfiltration control.
- Thinking SGs can deny a specific IP — they can't; use NACLs/WAF.
- One shared "default" SG for everything — every resource can talk to every other.
- Forgetting that removing a rule doesn't drop established connections.
📋 Quick Reference
stateful · allow-only · attached to ENIs · rules unioned · default: no in, all out
reference SGs for internal tiers; prefix lists for AWS-managed ranges
ALB(443 public) → app(port from sg-alb) → db(5432 from sg-app)
tighten egress; replace bastions with SSM Session Manager
NACL = stateless subnet guardrail with deny rules🧠 Key takeaways
- Security groups are stateful, allow-only firewalls attached to ENIs.
- Reference other security groups as sources instead of CIDRs: rules follow instances as IPs change.
- Build tiered chains (ALB → app → DB); never open databases or SSH to 0.0.0.0/0 (use SSM Session Manager).
- NACLs are stateless subnet-level filters with deny rules; use them sparingly as a coarse backstop.
🎤 Interview Q&A
Q1What is a security group?core▾
A stateful virtual firewall attached to ENIs (instances, load balancers, RDS, Lambda in VPC). It has only allow rules; return traffic is automatically allowed. Default: deny all inbound, allow all outbound.
- Can you write deny rules? No; use NACLs or network firewalls for explicit denies.
Q2Security groups vs network ACLs?core▾
Security groups: instance level, stateful, allow-only, all rules evaluated. NACLs: subnet level, stateless (configure both directions and ephemeral ports), allow and deny, rules evaluated in order.
- When use NACLs? Coarse subnet-wide blocks, e.g. denying a malicious IP range.
Q3How do you model a three-tier app with security groups?core▾
ALB SG allows 443 from the internet; app SG allows the app port only from the ALB SG; DB SG allows 5432 only from the app SG. Referencing SGs instead of IPs keeps rules correct as instances scale.
- Why reference SGs? IPs change with autoscaling; SG references don't.
Q4What are common security group mistakes?senior▾
0.0.0.0/0 on SSH/RDP or database ports, overly broad port ranges, unused rules left behind, and sharing one SG across unrelated services.
- How do you audit them? AWS Config rules, Security Hub, Trusted Advisor.
Q5Do security groups limit outbound traffic?core▾
Only if you replace the default allow-all outbound rule. Restricting egress limits data exfiltration and SSRF impact, though it requires knowing dependencies.
- Combine with? VPC endpoints and egress proxies.
🛠️ Practice exercises
Each exercise is a file in this topic folder. Code exercises are self-checking: run them and make the checks pass.
✅ Check yourself
Answer the questions — feedback is instant.