Security groups and network ACLs

Amazon Web Services · Essentials · 12 min

Correct firewall rules are the difference between a private database and a breach, and the first thing to check when traffic fails.

A security group (SG) is a virtual firewall attached to network interfaces (instances, load balancers, RDS, Lambda in a VPC, ECS tasks). Its properties:

  • Allow rules only. Anything not allowed is denied.
  • Stateful: if inbound traffic is allowed, the response is automatically allowed out, and vice versa.
  • New SGs allow all outbound and no inbound traffic.
  • A rule's source can be a CIDR, a prefix list or another security group. Referencing SGs is the idiomatic way to build tiers: the database SG allows port 5432 from the app SG, so any instance in the app tier can connect regardless of its IP, and nothing else can.

Changes apply immediately to existing connections' future packets, and one interface can have several SGs (the rules are combined).

Network ACLs sit at the subnet boundary. They are stateless, have numbered rules evaluated in order, and support explicit Deny. Because they're stateless you must allow return traffic yourself, typically the ephemeral port range 1024-65535. The default NACL allows everything, and most teams leave it that way, using SGs for real control and NACLs only for coarse subnet-wide blocks.

When something can't connect, check in this order: route tables, SG inbound on the target, SG outbound on the source, NACLs both ways, then the OS firewall and whether the process listens on the right interface. VPC Reachability Analyzer automates much of this.

Never open 0.0.0.0/0 to SSH, RDP or database ports.

Example

WEB=$(aws ec2 create-security-group --group-name web-alb --vpc-id vpc-0a1b2c3d \
  --description "Public HTTPS" --query GroupId --output text)
APP=$(aws ec2 create-security-group --group-name app --vpc-id vpc-0a1b2c3d \
  --description "App tier" --query GroupId --output text)

# Internet -> load balancer on 443
aws ec2 authorize-security-group-ingress --group-id "$WEB" \
  --protocol tcp --port 443 --cidr 0.0.0.0/0

# Load balancer SG -> app on 8080 (no IPs involved)
aws ec2 authorize-security-group-ingress --group-id "$APP" \
  --protocol tcp --port 8080 --source-group "$WEB"

aws ec2 describe-security-group-rules --filters Name=group-id,Values="$APP" \
  --query 'SecurityGroupRules[?!IsEgress].[FromPort,ReferencedGroupInfo.GroupId]' --output text
# 8080  sg-0web...

Remember

  • Security groups: allow-only, stateful, attached to interfaces
  • Reference security groups as sources to build tiers
  • NACLs: stateless, ordered, can deny, apply to whole subnets
  • Debug connectivity: routes, SGs, NACLs, then the host

Watch out for

  • Adding a NACL rule for inbound traffic but forgetting the outbound ephemeral ports for responses.

Check yourself

  1. An instance's SG allows inbound TCP 443 and has no outbound rules at all. Can clients get HTTPS responses?
  2. What is the best way to let only the app tier reach the database on 5432?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.aws.amazon.com/vpc/latest/userguide/vpc-security-groups.html

Security groups and network ACLs · Amazon Web Services · Topolearn