Chapter 5: Firewalls, NAT, and DMZ


Securing Network Boundaries

A network without security controls is an open door. Firewalls are the gatekeepers — they inspect traffic and enforce rules about what’s allowed in and out. Combined with NAT (Network Address Translation) for address management and DMZ (Demilitarized Zone) architecture for isolating public services, firewalls form the backbone of network security.

This chapter covers the theory and practical implementation of all three, with hands-on Linux examples.


Firewall Fundamentals

What a Firewall Does

A firewall examines network packets and decides whether to accept, drop, or reject them based on a set of rules. Rules typically match on:

Types of Firewalls

Type Layer Description
Packet filter L3–L4 Inspects individual packets (IP, port, protocol)
Stateful firewall L3–L4 Tracks connection state; allows related return traffic
Application firewall (WAF) L7 Inspects application-layer content (HTTP headers, payloads)
Next-gen firewall (NGFW) L3–L7 Combines stateful + application inspection + IDS/IPS

Linux’s built-in firewall is a stateful packet filter operating at Layers 3–4.


iptables

iptables is the traditional Linux firewall tool. It’s been the standard since 2001 and remains widely used.

Chains and Tables

iptables organizes rules into chains within tables:

Table Purpose Key Chains
filter (default) Accept/drop packets INPUT, FORWARD, OUTPUT
nat Network Address Translation PREROUTING, POSTROUTING, OUTPUT
mangle Packet header modification All chains
raw Skip connection tracking PREROUTING, OUTPUT

The three main chains in the filter table:

Basic iptables Rules

# View current rules
sudo iptables -L -n -v

# Set default policies (drop everything, then whitelist)
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

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

# Allow established and related connections
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Allow SSH (port 22)
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Allow HTTP and HTTPS
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Allow ping (ICMP)
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# Log and drop everything else
sudo iptables -A INPUT -j LOG --log-prefix "DROPPED: "
sudo iptables -A INPUT -j DROP

Saving and Restoring Rules

# Save current rules
sudo iptables-save > /etc/iptables/rules.v4

# Restore rules on boot
sudo iptables-restore < /etc/iptables/rules.v4

# On Debian/Ubuntu, install iptables-persistent for automatic restore
sudo apt install iptables-persistent

nftables — The Modern Replacement

nftables replaces iptables with a cleaner syntax, better performance, and unified handling of IPv4, IPv6, and ARP in a single framework.

nftables Basics

# List all rules
sudo nft list ruleset

# Create a table and chain
sudo nft add table inet filter
sudo nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }

# Allow loopback
sudo nft add rule inet filter input iif lo accept

# Allow established connections
sudo nft add rule inet filter input ct state established,related accept

# Allow SSH, HTTP, HTTPS
sudo nft add rule inet filter input tcp dport { 22, 80, 443 } accept

# Allow ICMP
sudo nft add rule inet filter input ip protocol icmp accept
sudo nft add rule inet filter input ip6 nexthdr icmpv6 accept

# Log dropped packets
sudo nft add rule inet filter input log prefix \"DROPPED: \" drop

nftables Configuration File

For persistent rules, write a configuration file:

#!/usr/sbin/nft -f
# /etc/nftables.conf

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;

        iif lo accept
        ct state established,related accept
        tcp dport { 22, 80, 443 } accept
        ip protocol icmp accept
        ip6 nexthdr icmpv6 accept
        log prefix "DROPPED: " drop
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}
sudo systemctl enable nftables
sudo systemctl start nftables

NAT — Network Address Translation

Why NAT?

With IPv4 address exhaustion, most organizations have only a few public IP addresses but many internal devices. NAT allows multiple devices on a private network to share a single public IP address by translating addresses at the network boundary.

Types of NAT

Type Description Use Case
SNAT (Source NAT) Rewrites source IP of outgoing packets Internal hosts accessing the Internet
DNAT (Destination NAT) Rewrites destination IP of incoming packets Port forwarding to internal servers
Masquerade Dynamic SNAT using the outgoing interface’s IP Home routers, dynamic public IPs
PAT (Port Address Translation) Maps multiple internal IPs to one public IP using different ports Most common form of NAT

NAT with iptables

# Enable IP forwarding
sudo sysctl -w net.ipv4.ip_forward=1

# SNAT / Masquerade — internal hosts access the Internet
# eth0 = public interface, eth1 = private interface
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# DNAT / Port forwarding — forward port 8080 to internal server
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 \
  -j DNAT --to-destination 192.168.1.100:80

# Allow forwarded traffic
sudo iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

NAT with nftables

table ip nat {
    chain prerouting {
        type nat hook prerouting priority -100; policy accept;
        tcp dport 8080 dnat to 192.168.1.100:80
    }

    chain postrouting {
        type nat hook postrouting priority 100; policy accept;
        oifname "eth0" masquerade
    }
}

DMZ — Demilitarized Zone

The DMZ Concept

A DMZ is a network segment that sits between the public Internet and your internal (trusted) network. It hosts services that need to be publicly accessible — web servers, mail servers, DNS servers — while keeping the internal network protected.

The key principle: if a DMZ server is compromised, the attacker still cannot directly access the internal network.

DMZ Architecture Patterns

Single Firewall DMZ

The simplest DMZ design uses one firewall with three interfaces:

                    Internet
                       │
                  [Firewall]
                 /     │     \
          [DMZ]    [Internal]  
       Web Server   Workstations
       Mail Server  Database

Firewall rules:

Dual Firewall DMZ

A more secure design uses two firewalls (ideally from different vendors to avoid a single vulnerability compromising both):

    Internet
       │
  [Firewall 1] ← External firewall
       │
    [DMZ]
       │
  [Firewall 2] ← Internal firewall
       │
  [Internal Network]

This provides defense in depth — an attacker must breach two independent firewalls to reach the internal network.

Implementing a DMZ on Linux

Here’s a practical example with nftables. Assume three interfaces:

table inet filter {
    chain forward {
        type filter hook forward priority 0; policy drop;

        # Internet → DMZ: allow HTTP/HTTPS only
        iifname "eth0" oifname "eth1" tcp dport { 80, 443 } accept

        # DMZ → Internet: allow (for updates, etc.)
        iifname "eth1" oifname "eth0" ct state established,related accept
        iifname "eth1" oifname "eth0" tcp dport { 80, 443 } accept

        # Internal → DMZ: allow (management)
        iifname "eth2" oifname "eth1" accept

        # DMZ → Internal: deny (critical isolation)
        iifname "eth1" oifname "eth2" drop

        # Internal → Internet: allow
        iifname "eth2" oifname "eth0" accept

        # Return traffic for established connections
        ct state established,related accept
    }
}

Full example: code/dmz_nftables.conf


Network Segmentation Best Practices

Beyond DMZ, network segmentation reduces blast radius when a breach occurs:

Segment Purpose Access Policy
DMZ Public-facing services Internet access, no internal access
Internal/Corporate User workstations Internet via proxy, limited server access
Server/Data Databases, app servers No direct Internet, accessed from internal/DMZ
Management Network devices, admin tools Restricted to IT staff
IoT/OT Sensors, cameras, industrial Isolated, minimal connectivity

Combine VLANs (Chapter 4) with firewall rules to enforce these boundaries.


Firewall Management in Python

You can automate firewall rule management with Python:

import subprocess

def add_allow_rule(port: int, protocol: str = "tcp") -> None:
    """Add an iptables rule to allow incoming traffic."""
    cmd = [
        "iptables", "-A", "INPUT",
        "-p", protocol,
        "--dport", str(port),
        "-j", "ACCEPT"
    ]
    subprocess.run(["sudo"] + cmd, check=True)
    print(f"Allowed {protocol}/{port}")

Full example: code/firewall_manager.py


Key Takeaways


← Previous: Switching, Routing, and VLANs Table of Contents Next: TLS, Encryption, and Certificates →