Networking Tutorial · Routing and Network Services · Lesson 18 of 28

Firewalls

Stateful and stateless firewalls, allow and deny rules, and why return traffic needs ephemeral ports.

Create a free account to save this page, take notes and track your progress. Sign in

Firewall rules

A firewall allows or blocks traffic by protocol, address range and port: "allow TCP 443 from anywhere", "allow TCP 5432 from 10.0.1.0/24".

Stateful versus stateless

  • A stateful firewall tracks connections. If it allows a request out, the replies are allowed back in automatically. Cloud security groups (AWS), network security groups (Azure) and VPC firewall rules (Google Cloud) are stateful.
  • A stateless firewall judges every packet on its own, so you must allow the replies explicitly. Replies go to the client's ephemeral port, so a stateless rule set needs a wide port range open for return traffic. AWS network ACLs are stateless.
Why stateless firewalls need ephemeral portsTry it yourself
def stateless(packet, rules):
    return any(packet["dir"] == r[0] and r[1] <= packet["port"] <= r[2] for r in rules)

def stateful(packet, rules, connections):
    if packet["dir"] == "in" and packet["conn"] in connections:
        return True                                   # reply to a connection we allowed out
    ok = stateless(packet, rules)
    if ok and packet["dir"] == "out":
        connections.add(packet["conn"])
    return ok

rules = [("out", 443, 443)]                           # allow HTTPS requests out, nothing else
request = {"dir": "out", "port": 443, "conn": "10.0.1.5:49152<->1.2.3.4:443"}
reply = {"dir": "in", "port": 49152, "conn": "10.0.1.5:49152<->1.2.3.4:443"}

print("stateless: request", stateless(request, rules), "| reply", stateless(reply, rules))
conns = set()
print("stateful:  request", stateful(request, rules, conns), "| reply", stateful(reply, rules, conns))
rules.append(("in", 1024, 65535))                     # the stateless fix: open ephemeral ports inbound
print("stateless with ephemeral range: reply", stateless(reply, rules))

Output

stateless: request True | reply False
stateful:  request True | reply True
stateless with ephemeral range: reply True

Good habits

  • Default deny: allow only what's needed.
  • Allow traffic from other security groups (by reference) instead of IP ranges where you can, so rules keep working when instances change.
  • Never open databases, SSH or admin ports to 0.0.0.0/0. Use a VPN, AWS Systems Manager Session Manager, Azure Bastion or Google Cloud IAP instead of public SSH.

Test yourself

Outbound HTTPS works through a security group but fails after adding a restrictive network ACL. What's the likely cause?

  1. The NACL doesn't allow inbound return traffic on ephemeral ports
  2. Security groups are stateless
  3. HTTPS needs UDP
  4. The route table has no local route
Show answer

Answer: The NACL doesn't allow inbound return traffic on ephemeral ports

NACLs are stateless: replies arrive on the client's ephemeral port and need an explicit inbound allow (for example 1024-65535).

Was this page helpful?