backend / networking / 07_firewalls_security_groups.md

Firewalls and Security Groups

5 interview angles 5 min read source

Firewalls and Security Groups

A firewall is a packet filter. It looks at packets and decides allow / deny based on rules over IP, port, protocol, and (for stateful firewalls) connection state.

In cloud, firewalls show up as Security Groups (instance-level, stateful) and NACLs (subnet-level, stateless). On Linux servers it’s iptables / nftables / ufw.

Stateful vs stateless

Stateful Stateless
Tracks connections? yes — knows what’s part of an existing flow no — every packet evaluated independently
Need an explicit return rule? no — return traffic auto-allowed yes — must allow inbound and outbound
Examples AWS Security Group, modern Linux iptables, home router AWS NACL, very old packet filters, DDoS scrubbing
Memory cost higher — connection table lower
Easier to reason about? yes “yes” if you like writing twice the rules

Default modern firewalls are stateful. Stateless is what you use when you need maximum throughput or to enforce per-direction policy at a coarser layer.

AWS: Security Groups vs NACLs

Both gate VPC traffic. They run in different places.

Security Group NACL
Attached to ENI / instance / RDS / Lambda subnet
Stateful? yes no — must allow ingress AND egress
Allow + deny? allow only (default deny) allow and deny rules, ordered
Default deny all in, allow all out allow all (until you tighten)
Rule reference other SGs by ID, CIDR CIDR only
Evaluation all rules across all SGs are unioned rules processed in order, first match wins

Security Groups are the primary firewall in a VPC. NACLs are a coarse extra layer (block a malicious IP at the subnet level, defense-in-depth).

Typical SG layout:

sg-web    : ingress 80, 443 from 0.0.0.0/0 ; egress all
sg-app    : ingress 8000 from sg-web         ; egress all
sg-db     : ingress 5432 from sg-app         ; egress all

Notice rules reference other security groups by ID, not by IP — that means the rule keeps working as instances scale up/down or get new IPs. This is the killer feature vs raw firewall rules.

The “default deny” model

Both Security Groups and most modern firewalls follow allow-listing:

  1. Start with everything denied.
  2. Add explicit allows for what you need.

The opposite (block-listing — deny known bad, allow rest) is a bottomless pit because the universe of “bad” is infinite.

iptables / nftables

# Allow established connections (the canonical first rule)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Allow loopback
iptables -A INPUT -i lo -j ACCEPT

# Allow SSH from a specific IP
iptables -A INPUT -p tcp --dport 22 -s 198.51.100.5 -j ACCEPT

# Allow HTTP/HTTPS from anywhere
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Drop everything else
iptables -A INPUT -j DROP

nftables is the modern replacement (single tool for IPv4/IPv6, faster). ufw is a friendlier wrapper.

Ingress vs egress

Direction What it controls
Ingress inbound — “who can connect TO this host”
Egress outbound — “who/what can this host connect TO”

Most teams obsess over ingress (web-facing port 443) and forget egress. Egress filtering matters because:

  • A compromised app server with open egress can exfiltrate data anywhere.
  • Same for SSRF attacks (the app fetches an attacker URL).
  • Many compliance regimes (PCI, HIPAA) require egress restrictions.

Sensible egress allowlist for an internal service: outbound to your DB SG, your cache SG, and specific external APIs (by IP if static, or via a proxy). No 0.0.0.0/0.

Security Group composition

You can attach multiple SGs to one instance. The effective rules are the union of all of them. So:

SG-base    : ingress 22 from corp-VPN
SG-web     : ingress 80, 443 from 0.0.0.0/0
SG-monitor : ingress 9100 from prometheus-SG

instance gets: 22 + 80 + 443 + 9100

Compose like Lego instead of writing one mega-SG per role.

Common interview confusions

  • “NACLs replace Security Groups.” — no, they’re complementary. SG is the primary stateful firewall; NACL is a coarse stateless subnet-level extra.
  • “My SG egress allows all, why can’t my instance reach the Internet?” — egress rule is necessary but not sufficient. You also need a route to the Internet (Internet Gateway for public, NAT Gateway for private). See 04_nat.md, 09_vpc_cloud_networking.md.
  • “My instance has SSH allowed in SG, why is the connection hanging?” — could be NACL, route table, public IP missing, SG allows the wrong CIDR, or your local egress is blocked. SG is one of many layers.
  • “Stateful firewall doesn’t need an outbound rule for the response.” — correct. The state table maps the inbound connection and lets responses through automatically.

Diagnosing “blocked by firewall”

The hierarchy of “why can’t A talk to B” in AWS:

  1. Source SG egress allows it?
  2. Subnet NACL outbound allows it?
  3. Route exists from source subnet to destination?
  4. Subnet NACL inbound (on destination side) allows it?
  5. Destination SG ingress allows it?
  6. Application is actually listening?

Any one no = silent drop (firewalls drop, they don’t reply). Use VPC Flow Logs to see which leg fails. See 14_troubleshooting_tools.md.

Interview angle

  • “Stateful vs stateless firewall?” — stateful tracks connections so return packets are auto-allowed; stateless evaluates each packet alone, so you must write ingress AND egress rules.
  • “Security Group vs NACL in AWS?” — SG is stateful, attached to ENI/instance, allow-only, can reference other SGs. NACL is stateless, attached to subnet, allow+deny ordered, CIDR-only. SG is the primary firewall; NACL is a coarse extra.
  • “How would you set up SGs for a 3-tier app (web / app / db)?” — sg-web (ingress 80/443 from 0.0.0.0/0), sg-app (ingress 8000 from sg-web), sg-db (ingress 5432 from sg-app). Reference SGs by ID so it works as instances scale.
  • “Why filter egress when ingress is the obvious threat?” — limits blast radius of compromised servers (data exfiltration, SSRF, malware C2), required by many compliance frameworks.
  • “Your app can’t reach RDS — walk through the layers.” — app SG egress → app subnet NACL out → route to DB subnet → DB subnet NACL in → DB SG ingress → Postgres listening + accepting that user.