Skip to content

Firewalls

Chapter 23: Firewalls - iptables, nftables, firewalld

Section titled “Chapter 23: Firewalls - iptables, nftables, firewalld”

Comprehensive Linux Firewall Management for Production Environments

Section titled “Comprehensive Linux Firewall Management for Production Environments”

23.1 Understanding Linux Firewall Architecture

Section titled “23.1 Understanding Linux Firewall Architecture”

Linux firewalls operate at multiple layers of the networking stack, providing defense-in-depth protection for your systems. Understanding how packets flow through the Linux kernel is crucial for effective firewall management.

Linux Packet Flow Through Netfilter
+------------------------------------------------------------------+
| |
| Incoming Packet |
| | |
| v |
| +------------------+ |
| | Network Card | (Physical layer - eth0, wlan0) |
| +------------------+ |
| | |
| v |
| +------------------+ |
| | PREROUTING | (mangle/nat - Before routing decision) |
| | (mangle table) | |
| | (nat table) | |
| +------------------+ |
| | |
| v |
| +------------------+ |
| | Routing Decision| (Local or Forward?) |
| +------------------+ |
| | | |
| | v |
| | +------------------+ |
| | | FORWARD Chain | (routed to another |
| | | (filter table) | interface) |
| | +------------------+ |
| | | |
| v v |
| +------------------+ +------------------+ |
| | INPUT Chain | | POSTROUTING | |
| | (filter table) | | (nat table) | |
| +------------------+ +------------------+ |
| | | |
| v v |
| +------------------+ +------------------+ |
| | Local Process | | Outgoing Packet | |
| +------------------+ +------------------+ |
| |
| Tables (in order of processing): |
| 1. mangle - Packet modification (TTL, marks) |
| 2. nat - Network Address Translation |
| 3. filter - Packet filtering (default) |
| 4. security - SELinux contexts |
| 5. raw - Connection tracking exemptions |
| |
+------------------------------------------------------------------+
iptables Tables Overview
+------------------------------------------------------------------+
| |
| Table | Chains Available | Purpose |
| -------------|---------------------------|---------------------|
| filter | INPUT, OUTPUT, FORWARD | Packet filtering |
| nat | PREROUTING, OUTPUT, | Port forwarding, |
| | POSTROUTING | Masquerading |
| mangle | PREROUTING, OUTPUT, | Packet alteration |
| | INPUT, FORWARD | (TTL, marks, TOS) |
| raw | PREROUTING, OUTPUT | Disable tracking |
| security | INPUT, OUTPUT, FORWARD | SELinux marks |
| |
| Default table for most operations is 'filter' |
| |
+------------------------------------------------------------------+

The iptables command follows a consistent pattern that you’ll use for most operations:

iptables Command Syntax
+------------------------------------------------------------------+
| |
| iptables [-t table] -A|-I|-D|-R|-L [chain] [options] [-j target]
| |
| Flags: |
| +----------------------------------------------------------+ |
| | -t, --table | Table to use (filter, nat, mangle, raw) | |
| | -A, --append | Add rule to end of chain | |
| | -I, --insert | Insert rule at position | |
| | -D, --delete | Delete rule | |
| | -R, --replace | Replace rule at position | |
| | -L, --list | List all rules | |
| | -F, --flush | Flush all rules | |
| | -N, --new-chain| Create new chain | |
| | -X, --delete-chain| Delete custom chain | |
| | -P, --policy | Set default policy | |
| | -v, --verbose | Verbose output | |
| | -n, --numeric | Don't resolve hostnames | |
| | --line-numbers | Show line numbers | |
| +----------------------------------------------------------+ |
| |
| Jump Targets (-j): |
| +----------------------------------------------------------+ |
| | ACCEPT | Allow packet | |
| | DROP | Silently discard | |
| | REJECT | Reject with error | |
| | LOG | Log to syslog | |
| | SNAT | Source NAT (post-routing) | |
| | DNAT | Destination NAT (pre-routing) | |
| | MASQUERADE| Auto-SNAT (dynamic IPs) | |
| | REDIRECT | Local redirect | |
| | RETURN | Return from custom chain | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
iptables Match Criteria
+------------------------------------------------------------------+
| |
| Protocol Matches: |
| -p, --protocol tcp|udp|icmp|all |
| |
| Source/Destination: |
| -s, --source IP address or network |
| -d, --destination IP address or network |
| |
| Port Matches: |
| --sport, --source-port Source port (with -p) |
| --dport, --destination-port Destination port (with -p) |
| -m multiport --dports 80,443,8080 (multiple ports) |
| |
| Interface: |
| -i, --in-interface Input interface (eth0, lo) |
| -o, --out-interface Output interface |
| |
| TCP Flags: |
| --tcp-flags SYN,ACK,FIN,RST,URG,PSH |
| |
| ICMP Type: |
| --icmp-type echo-request, echo-reply, destination-unreachable|
| |
| Connection State: |
| -m conntrack --ctstate NEW,ESTABLISHED,RELATED,INVALID |
| |
| Additional Matches: |
| -m limit --limit 3/minute Rate limiting |
| -m string --string "attack" Content matching |
| -m time --timestart 09:00 --timestop 17:00 Time-based |
| -m layer7 --l7proto http Application layer |
| |
+------------------------------------------------------------------+
Terminal window
# Flush existing rules first
sudo iptables -F
sudo iptables -X
sudo iptables -t nat -F
sudo iptables -t mangle -F
# Set default policies (DROP everything by default)
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
# Allow loopback interface
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT
# Allow established and related connections
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow SSH (change default port if needed)
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -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 ICMP (ping) - limit rate to prevent ping flood
sudo iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
# Allow specific IP ranges
sudo iptables -A INPUT -s 10.0.0.0/8 -j ACCEPT
sudo iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT
# Log dropped packets
sudo iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables-dropped: " --log-level 4
Terminal window
# Limit new SSH connections to prevent brute force (max 3 per minute)
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m recent --set --name SSH
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
# Limit HTTP requests per IP (100 connections per minute)
sudo iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW \
-m hashlimit --hashlimit-above 100/min --hashlimit-burst 50 \
--hashlimit-htable-size 100000 --hashlimit-name http_limit -j DROP
# Protect against SYN flood
sudo iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW \
-m limit --limit 1/s --limit-burst 3 -j ACCEPT
sudo iptables -A INPUT -p tcp --syn -j DROP
Terminal window
# Enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# Forward port 8080 to internal web server at 10.0.0.10:80
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.10:80
sudo iptables -A FORWARD -p tcp --dport 80 -d 10.0.0.10 -j ACCEPT
# Masquerade for outbound traffic (NAT for internal network)
sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
# Port forwarding for Docker (if using docker0 bridge)
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80
Terminal window
# Create custom chains for better organization
sudo iptables -N TCP
sudo iptables -N UDP
sudo iptables -N INVALID_DROP
# Route protocol-specific traffic to custom chains
sudo iptables -A INPUT -p tcp -j TCP
sudo iptables -A INPUT -p udp -j UDP
sudo iptables -A INPUT -m conntrack --ctstate INVALID -j INVALID_DROP
# In TCP chain - allow specific ports
sudo iptables -A TCP -p tcp --dport 22 -j ACCEPT
sudo iptables -A TCP -p tcp --dport 80 -j ACCEPT
sudo iptables -A TCP -p tcp --dport 443 -j ACCEPT
sudo iptables -A TCP -p tcp -j RETURN
# In UDP chain - allow DNS
sudo iptables -A UDP -p udp --dport 53 -j ACCEPT
sudo iptables -A UDP -p udp -j RETURN
# In INVALID_DROP chain
sudo iptables -A INVALID_DROP -j DROP
Terminal window
# Save rules (Debian/Ubuntu)
sudo iptables-save > /etc/iptables/rules.v4
# Save rules (RHEL/CentOS)
sudo iptables-save > /etc/sysconfig/iptables
# Restore rules (Debian/Ubuntu)
sudo iptables-restore < /etc/iptables/rules.v4
# Restore rules (RHEL/CentOS)
sudo iptables-restore < /etc/sysconfig/iptables
# Make rules persistent across reboots (Ubuntu)
sudo apt-get install iptables-persistent
# or on RHEL
sudo systemctl enable iptables
Terminal window
# RHEL/CentOS - iptables service
sudo systemctl start iptables
sudo systemctl enable iptables
sudo systemctl status iptables
sudo systemctl restart iptables
# View current rules
sudo iptables -L -n -v --line-numbers
sudo iptables -t nat -L -n -v
sudo iptables -t mangle -L -n -v
# Check specific chain
sudo iptables -L INPUT -n -v
sudo iptables -L OUTPUT -n -v
# Delete rules by line number
sudo iptables -D INPUT 5
# Replace rule by line number
sudo iptables -R INPUT 3 -p tcp --dport 22 -j ACCEPT

nftables is the modern successor to iptables, designed to address several limitations of the legacy tool:

iptables vs nftables Comparison
+------------------------------------------------------------------+
| |
| Feature | iptables | nftables |
| -----------------|------------------|-------------------------|
| Architecture | Separate binaries | Single tool (nft) |
| Tables | Separate tables | Unified framework |
| Ruleset | Fragmented | Single file |
| Performance | Linear lookup | Fast lookup (hash) |
| Backward compat | N/A | iptables compatibility |
| Extensibility | Kernel modules | Netlink API |
| Numeric output | IP-only | Handles, sets, maps |
| |
| nftables Advantages: |
| +----------------------------------------------------------+ |
| | 1. Single tool for IPv4, IPv6, ARP, bridge, inet | |
| | 2. Atomic rule set replacement | |
| | 3. Built-in sets and maps for efficient matching | |
| | 4. Better performance with rule set numbering | |
| | 5. Simplified syntax | |
| | 6. Improved debugging and tracing | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
nft Command Syntax
+------------------------------------------------------------------+
| |
| nft [options] [command] [rule-specification] |
| |
| Commands: |
| +----------------------------------------------------------+ |
| | -a, --add | Add rule | |
| | -d, --delete | Delete rule or table | |
| | -l, --list | List rules or tables | |
| | -f, --file | Read from file | |
| | -i, --interactive | Interactive mode | |
| | -I, --insert | Insert rule | |
| | -r, --replace | Replace rule | |
| | -F, --flush | Flush rules | |
| | -T, --table | Table name | |
| | -c, --check | Check rules without applying | |
| | -v, --verbose | Verbose output | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
nftables Table/Chain Structure
+------------------------------------------------------------------+
| |
| Family | Table Prefix | Example |
| ------------|--------------|---------------------------------|
| ip | ip | table ip filter |
| ip6 | ip6 | table ip6 filter |
| inet | inet | table inet filter (both v4/v6) |
| arp | arp | table arp filter |
| bridge | bridge | table bridge filter |
| |
| Chain Types: |
| +----------------------------------------------------------+ |
| | filter | Packet filtering | |
| | nat | Network Address Translation | |
| | route | Routing decisions (FORWARD) | |
| +----------------------------------------------------------+ |
| |
| Chain Hooks: |
| +----------------------------------------------------------+ |
| | prerouting | Before routing decision | |
| | input | Incoming packets to local | |
| | forward | Packets being forwarded | |
| | output | Outgoing packets from local | |
| | postrouting| After routing decision | |
| +----------------------------------------------------------+ |
| |
| Priorities (lower = first): |
| +----------------------------------------------------------+ |
| | raw -10000 | filter 0 | |
| | dstnat -100 | security 50 | |
| | prerouting -100 | out 100 | |
| | native 0 (default) | | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
Terminal window
# Create a basic filter table
sudo nft add table ip filter
# Create chains with hooks and priorities
sudo nft add chain ip filter input { type filter hook input priority 0; policy drop; }
sudo nft add chain ip filter forward { type filter hook forward priority 0; policy drop; }
sudo nft add chain ip filter output { type filter hook output priority 0; policy accept; }
# For both IPv4 and IPv6 (inet family)
sudo nft add table inet my_firewall
sudo nft add chain inet my_firewall input { type filter hook input priority 0; policy drop; }
Terminal window
# Allow loopback
sudo nft add rule ip filter input iif lo accept
# Allow established/related connections
sudo nft add rule ip filter input ct state established,related accept
# Allow SSH
sudo nft add rule ip filter input tcp dport 22 ct state new accept
# Allow HTTP/HTTPS
sudo nft add rule ip filter input tcp dport { 80, 443 } accept
# Allow ICMP (ping)
sudo nft add rule ip filter input icmp type echo-request limit rate 1/second accept
# Allow specific IP
sudo nft add rule ip filter input ip saddr 10.0.0.5 accept
# Log and drop everything else
sudo nft add rule ip filter input counter drop
Terminal window
# Define a set of blocked IPs
sudo nft add set ip filter blocked_ips { type ipv4_addr; }
# Add IPs to the set
sudo nft add element ip filter blocked_ips { 192.168.1.100, 10.0.0.50 }
# Block traffic from blocked IPs
sudo nft add rule ip filter input ip saddr @blocked_ips drop
# Define a set of allowed ports
sudo nft add set ip filter allowed_ports { type inet_service; }
# Dynamic port forwarding with map
sudo nft add table ip nat
sudo nft add chain ip nat prerouting { type nat hook prerouting priority -100; }
sudo nft add rule ip nat prerouting tcp dport 8080 dnat to 10.0.0.10:80
Terminal window
# NAT table for port forwarding
sudo nft add table ip nat
# DNAT - Port forward 8080 to internal server
sudo nft add chain ip nat prerouting { type nat hook prerouting priority -100; }
sudo nft add rule ip nat prerouting iif eth0 tcp dport 8080 dnat to 10.0.0.10:80
# SNAT - Masquerade for outbound traffic
sudo nft add chain ip nat postrouting { type nat hook postrouting priority 100; }
sudo nft add rule ip nat postrouting oif eth0 masquerade
#!/usr/sbin/nft -f
# Flush existing rules
flush ruleset
# Create tables
table inet filter {
# INPUT chain
chain input {
type filter hook input priority 0; policy drop;
# Loopback
iif lo accept
# Established/related
ct state established,related accept
# Invalid
ct state invalid drop
# ICMP
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
# SSH with rate limiting
tcp dport 22 ct state new limit rate 3/minute accept
# HTTP/HTTPS
tcp dport { 80, 443 } accept
# Log dropped
counter drop
}
# FORWARD chain
chain forward {
type filter hook forward priority 0; policy drop;
ct state established,related accept
counter drop
}
# OUTPUT chain
chain output {
type filter hook output priority 0; policy accept;
}
}
Terminal window
# List all rules
sudo nft list ruleset
sudo nft list table ip filter
sudo nft list chain ip filter input
# View with handles (for deletion)
sudo nft -a list table ip filter
sudo nft -a list chain ip filter input
# Delete specific rule by handle
sudo nft delete rule ip filter input handle 5
# Save rules to file
sudo nft list ruleset > /etc/nftables.conf
# Load rules from file
sudo nft -f /etc/nftables.conf
# Make persistent (systemd)
sudo systemctl enable nftables
sudo systemctl start nftables

23.4 firewalld - The Dynamic Firewall Manager

Section titled “23.4 firewalld - The Dynamic Firewall Manager”

firewalld provides a dynamically managed firewall with support for network zones. It’s the default firewall on RHEL, CentOS, and Fedora systems.

firewalld Architecture
+------------------------------------------------------------------+
| |
| firewalld Components |
| |
| +-------------------------------------------------------------+|
| | firewalld daemon ||
| | +------------------------------------------------------+ ||
| | | Firewall Backend (nftables or iptables) | ||
| | +------------------------------------------------------+ ||
| | | ||
| | +---------v--------+ ||
| | | D-Bus API | (For configuration) ||
| | +-----------------+ ||
| | | ||
| | +---------v--------+ ||
| | | firewall-cmd | (Command line) ||
| | | firewall-config | (GUI) ||
| | +-----------------+ ||
| +------------------------------------------------------------+|
| |
| Zones (Predefined Security Levels): |
| +----------------------------------------------------------+ |
| | drop | Block all, allow only outgoing | |
| | block | Reject all, allow only outgoing | |
| | public | Untrusted, selective incoming | |
| | external | For routers, with NAT | |
| | dmz | Public servers, limited internal access | |
| | work | Mostly trusted, limited incoming | |
| | home | Home network, more trust | |
| | internal | Internal network, most trust | |
| | trusted | Allow everything | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
Terminal window
# Check status
sudo firewall-cmd --state
sudo firewall-cmd --list-all
sudo firewall-cmd --list-all-zones
# Get current zone
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --get-default-zone
# Change default zone
sudo firewall-cmd --set-default-zone=work
# Add interface to zone
sudo firewall-cmd --zone=public --add-interface=eth0
sudo firewall-cmd --zone=public --change-interface=eth0
sudo firewall-cmd --zone=public --remove-interface=eth0
# Reload firewall (lose runtime changes)
sudo firewall-cmd --reload
# Complete reload
sudo firewall-cmd --complete-reload
Terminal window
# List allowed services
sudo firewall-cmd --list-services
# Add/remove services
sudo firewall-cmd --zone=public --add-service=ssh
sudo firewall-cmd --zone=public --remove-service=ssh
sudo firewall-cmd --zone=public --add-service=http
sudo firewall-cmd --zone=public --add-service=https
# List available services
sudo firewall-cmd --get-services
# Add custom service (create in /etc/firewalld/services/)
sudo firewall-cmd --zone=public --add-service=custom-app
Terminal window
# List open ports
sudo firewall-cmd --list-ports
# Add/remove ports
sudo firewall-cmd --zone=public --add-port=8080/tcp
sudo firewall-cmd --zone=public --remove-port=8080/tcp
# Add port range
sudo firewall-cmd --zone=public --add-port=1000-2000/tcp
# Permanent changes (survive reload)
sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp
sudo firewall-cmd --reload # Apply permanent changes
Rich Rule Syntax
+------------------------------------------------------------------+
| |
| firewalld rich rule format: |
| |
| rule [family="ipv4|ipv6"] |
| [source address="address[/mask]"] |
| [destination address="address[/mask]"] |
| [service name="service_name"] |
| [port port="portid" protocol="tcp|udp"] |
| [icmp-block name="icmptype"] |
| [masquerade] |
| [forward-port port="portid" protocol="tcp|udp" |
| to-addr="address" to-port="portid"] |
| [log [prefix="text"] [level="log|emerg|alert|crit|error| |
| warning|notice|info"]] |
| [audit [limit value="rate/duration"]] |
| [accept | reject [type="reject_type"] | drop] |
| |
+------------------------------------------------------------------+
Terminal window
# Allow SSH from specific IP
sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="10.0.0.5" service name="ssh" accept'
# Rate limit SSH connections
sudo firewall-cmd --zone=public --add-rich-rule='rule service name="ssh" accept limit value="3/m"'
# Block specific IP
sudo firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.100" drop'
# Port forwarding
sudo firewall-cmd --zone=external --add-forward-port=port=8080:proto=tcp:toport=80:toaddr=10.0.0.10
# Masquerading
sudo firewall-cmd --zone=external --add-masquerade
# Log and reject
sudo firewall-cmd --zone=public --add-rich-rule='rule service name="ssh" log prefix="SSH: " level="info" accept'
# List rich rules
sudo firewall-cmd --zone=public --list-rich-rules
Terminal window
# Enable forwarding in kernel
echo 1 > /proc/sys/net/ipv4/ip_forward
# Make permanent
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p
# Forward port 80 to internal server
sudo firewall-cmd --zone=external --add-forward-port=port=80:proto=tcp:toport=80:toaddr=10.0.0.10
sudo firewall-cmd --zone=external --add-masquerade
# Permanent (survive reboot)
sudo firewall-cmd --permanent --zone=external --add-forward-port=port=80:proto=tcp:toport=80:toaddr=10.0.0.10
sudo firewall-cmd --permanent --zone=external --add-masquerade
sudo firewall-cmd --reload
Terminal window
# Add direct iptables rule
sudo firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 22 -j ACCEPT
# Add rule to chain
sudo firewall-cmd --direct --add-chain ipv4 filter my_custom_chain
# List direct rules
sudo firewall-cmd --direct --get-all-rules
sudo firewall-cmd --direct --list-rules ipv4 filter INPUT
# Remove direct rule
sudo firewall-cmd --direct --remove-rule ipv4 filter INPUT 0 -p tcp --dport 22 -j ACCEPT
Terminal window
# Create custom service file
sudo vi /etc/firewalld/services/custom-app.xml
# Content:
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>Custom App</short>
<description>Custom application service</description>
<port port="9000" protocol="tcp"/>
<port port="9001" protocol="udp"/>
</service>
# Reload and use
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --add-service=custom-app

UFW provides a simplified interface for managing iptables rules. It’s the default on Ubuntu and Debian systems.

Terminal window
# Enable/disable UFW
sudo ufw enable
sudo ufw disable
# Check status
sudo ufw status
sudo ufw status verbose
sudo ufw status numbered
# Default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw default deny routed # For forward chain
Terminal window
# Allow SSH (both)
sudo ufw allow ssh
sudo ufw allow 22/tcp
# Allow specific ports
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 8000:9000/tcp # Port range
# Deny specific port
sudo ufw deny 23/tcp # Telnet
# Allow from specific IP
sudo ufw allow from 10.0.0.5
sudo ufw allow from 10.0.0.0/24
# Allow specific IP to port
sudo ufw allow from 10.0.0.5 to any port 22
# Deny from specific IP
sudo ufw deny from 192.168.1.100
# Delete rules
sudo ufw delete allow 22/tcp
sudo ufw delete deny from 192.168.1.100
Terminal window
# List available profiles
sudo ufw app list
sudo ufw app info "Nginx Full"
# Allow using profile
sudo ufw allow "Nginx Full"
sudo ufw allow "OpenSSH"
# Create custom profile
sudo vi /etc/ufw/applications.d/custom-app
[Custom App]
title=Custom Application
description=Custom app ports
ports=9000,9001/tcp
Terminal window
# Main config
sudo vi /etc/ufw/ufw.conf
# Rules location
/etc/ufw/user.rules # IPv4
/etc/ufw/user6.rules # IPv6
/etc/ufw/before.rules # Before user rules
/etc/ufw/after.rules # After user rules
# Logging
sudo ufw logging on
sudo ufw logging off
sudo ufw logging low|medium|high
# View logs
sudo tail -f /var/log/ufw.log

Production Firewall Checklist
+------------------------------------------------------------------+
| |
| Initial Setup: |
| +----------------------------------------------------------+ |
| | □ Default deny all incoming traffic | |
| | □ Default allow all outgoing traffic | |
| | □ Log and drop invalid packets | |
| | □ Rate limit new connections | |
| | □ Allow only necessary ports | |
| | □ Restrict SSH to known IPs or use key-based auth | |
| +----------------------------------------------------------+ |
| |
| Essential Rules: |
| +----------------------------------------------------------+ |
| | □ Allow loopback interface | |
| | □ Allow established/related connections | |
| | □ Allow SSH (port 22 or custom) | |
| | □ Allow HTTP/HTTPS (80, 443) | |
| | □ Allow ICMP with rate limiting | |
| | □ Block common attack ports (telnet 23, rpc 111) | |
| +----------------------------------------------------------+ |
| |
| Security Enhancements: |
| +----------------------------------------------------------+ |
| | □ SYN flood protection | |
| | □ Port scanning detection | |
| | □ Connection tracking limits | |
| | □ Application-layer filtering | |
| | □ Fail2Ban integration | |
| | □ Regular audit of firewall rules | |
| +----------------------------------------------------------+ |
| |
| High Availability: |
| +----------------------------------------------------------+ |
| | □ Document all rules | |
| | □ Backup firewall configuration | |
| | □ Test restore procedures | |
| | □ Automate deployment with configuration management | |
| | □ Monitor rule changes | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
Terminal window
# Install Fail2Ban
sudo apt-get install fail2ban # Debian/Ubuntu
sudo yum install fail2ban # RHEL/CentOS
# Configure jail.local
sudo vi /etc/fail2ban/jail.local
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = ssh
action = %(action_mwl)s
[nginx-http-auth]
enabled = true
[nginx-noscript]
enabled = true
# Start service
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# Check status
sudo fail2ban-client status
sudo fail2ban-client status sshd
Common Service Firewall Rules
+------------------------------------------------------------------+
| |
| Web Server (Apache/Nginx): |
| +----------------------------------------------------------+ |
| | iptables: | |
| | iptables -A INPUT -p tcp --dport 80 -j ACCEPT | |
| | iptables -A INPUT -p tcp --dport 443 -j ACCEPT | |
| | | |
| | firewalld: | |
| | firewall-cmd --permanent --add-service=http | |
| | firewall-cmd --permanent --add-service=https | |
| +----------------------------------------------------------+ |
| |
| Database Server (MySQL/PostgreSQL): |
| +----------------------------------------------------------+ |
| | iptables (allow only app server): | |
| | iptables -A INPUT -p tcp -s 10.0.0.5 --dport 3306 -j ACCEPT | |
| | | |
| | firewalld: | |
| | firewall-cmd --permanent --add-port=3306/tcp | |
| | firewall-cmd --permanent --add-rich-rule='rule family="ipv4" | |
| | source address="10.0.0.5" port port="3306" protocol="tcp" accept' | |
| +----------------------------------------------------------+ |
| |
| Mail Server: |
| +----------------------------------------------------------+ |
| | iptables: | |
| | iptables -A INPUT -p tcp --dport 25 -j ACCEPT | |
| | iptables -A INPUT -p tcp --dport 587 -j ACCEPT | |
| | iptables -A INPUT -p tcp --dport 993 -j ACCEPT | |
| | | |
| | firewalld: | |
| | firewall-cmd --permanent --add-service=smtp | |
| | firewall-cmd --permanent --add-service=smtps | |
| | firewall-cmd --permanent --add-service=imap | |
| | firewall-cmd --permanent --add-service=imaps | |
| +----------------------------------------------------------+ |
| |
| Docker: |
| +----------------------------------------------------------+ |
| | # Docker modifies iptables automatically | |
| | # Restrict container network access: | |
| | docker network create --internal internal-net | |
| | | |
| | # Expose only necessary ports | |
| | docker run -p 8080:80 mywebapp | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
Terminal window
# Check if firewall is blocking
sudo iptables -L -n -v | grep DROP
sudo iptables -L -n -v | grep REJECT
# Check connection states
sudo conntrack -L
sudo conntrack -L | grep ESTABLISHED
# Monitor dropped packets
sudo tcpdump -i eth0 -n | grep DROP
# Check system logs
sudo journalctl -u firewalld
sudo tail -f /var/log/ufw.log
sudo dmesg | grep iptables
# Test connectivity
nc -zv target_host port
telnet target_host port
curl -v http://target:port
# Verify listening ports
sudo ss -tulpn
sudo netstat -tulpn

  1. What is the difference between iptables and firewalld?

    • iptables is a direct interface to netfilter, using separate tables and chains
    • firewalld is a dynamic wrapper that manages rules dynamically with zones
  2. What are the default chains in the filter table?

    • INPUT: For packets destined for local socket
    • OUTPUT: For locally generated packets
    • FORWARD: For packets being routed through the system
  3. What is the difference between DROP and REJECT?

    • DROP silently discards the packet (no response)
    • REJECT sends an ICMP error message back to the source
  4. What is Connection Tracking (conntrack)?

    • Tracks the state of network connections (NEW, ESTABLISHED, RELATED, INVALID)
    • Essential for stateful packet filtering
  1. Explain the packet flow through iptables chains

    • Packet arrives → PREROUTING (mangle, nat) → Routing Decision → INPUT/FORWARD → OUTPUT → POSTROUTING
  2. How do you forward traffic from port 80 to an internal server?

    • Using DNAT: iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.0.0.10:80
    • Using firewalld: firewall-cmd --add-forward-port=port=80:proto=tcp:toport=80:toaddr=10.0.0.10
  3. What is NAT? Types of NAT?

    • Network Address Translation
    • SNAT: Source NAT (outbound traffic)
    • DNAT: Destination NAT (inbound traffic)
    • MASQUERADE: Dynamic SNAT
  4. How do you rate limit connections in iptables?

    • Using limit module: -m limit --limit 1/s --limit-burst 3
    • Using recent module: -m recent --set --name SSH and --update --seconds 60 --hitcount 4
  1. What are the advantages of nftables over iptables?

    • Single tool for all families (IPv4, IPv6, ARP, bridge)
    • Better performance with built-in sets and maps
    • Atomic rule set replacement
    • Simplified syntax and improved debugging
  2. How do you secure SSH against brute force attacks?

    • Use key-based authentication
    • Rate limit with iptables/firewalld
    • Change default port
    • Use Fail2Ban
    • Configure TCP wrappers
    • Disable root login
  3. Explain the concept of zones in firewalld

    • Zones define trust levels for network connections
    • Each zone has its own set of rules
    • Interfaces can be assigned to zones
    • Predefined zones: drop, block, public, external, dmz, work, home, internal, trusted
  4. How would you debug firewall rule issues?

    • Check current rules: iptables -L -n -v
    • Use logging: -j LOG --log-prefix
    • Check conntrack state: conntrack -L
    • Monitor with tcpdump
    • Check system logs
    • Use rule counters to identify matching rules

Web Server Firewall Configuration
+------------------------------------------------------------------+
| |
| Requirements: |
| - Allow HTTP (80) and HTTPS (443) from anywhere |
| - Allow SSH (22) from admin network only |
| - Allow ping for monitoring |
| - Block all other incoming traffic |
| |
| iptables solution: |
| +----------------------------------------------------------+ |
| | #!/bin/bash | |
| | # Flush rules | |
| | iptables -F | |
| | iptables -X | |
| | | |
| | # Default policies | |
| | iptables -P INPUT DROP | |
| | iptables -P FORWARD DROP | |
| | iptables -P OUTPUT ACCEPT | |
| | | |
| | # Loopback | |
| | iptables -A INPUT -i lo -j ACCEPT | |
| | | |
| | # Established | |
| | iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT | |
| | | |
| | # SSH from admin network only | |
| | iptables -A INPUT -p tcp -s 10.0.0.0/24 --dport 22 -m conntrack --ctstate NEW -j ACCEPT | |
| | | |
| | # HTTP/HTTPS | |
| | iptables -A INPUT -p tcp --dport 80 -j ACCEPT | |
| | iptables -A INPUT -p tcp --dport 443 -j ACCEPT | |
| | | |
| | # ICMP (ping) with rate limit | |
| | iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT | |
| +----------------------------------------------------------+ |
| |
| firewalld solution: |
| +----------------------------------------------------------+ |
| | firewall-cmd --set-default-zone=public | |
| | firewall-cmd --permanent --add-service=http | |
| | firewall-cmd --permanent --add-service=https | |
| | firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.0/24" service name="ssh" accept' | |
| | firewall-cmd --reload | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
NAT Router Setup
+------------------------------------------------------------------+
| |
| Network Setup: |
| +----------------------------------------------------------+ |
| | External: eth0 (WAN) - 203.0.113.10 | |
| | Internal: eth1 (LAN) - 192.168.1.1 | |
| +----------------------------------------------------------+ |
| |
| Requirements: |
| - NAT for all outbound traffic (masquerade) |
| - Forward port 8080 to internal web server |
| - Forward port 2201 to internal SSH server |
| |
| iptables solution: |
| +----------------------------------------------------------+ |
| | # Enable forwarding | |
| | echo 1 > /proc/sys/net/ipv4/ip_forward | |
| | | |
| | # NAT (masquerade) | |
| | iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE | |
| | | |
| | # Port forwarding: Web server | |
| | iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.10:80 | |
| | iptables -A FORWARD -p tcp --dport 80 -d 192.168.1.10 -j ACCEPT | |
| | | |
| | # Port forwarding: SSH server | |
| | iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 2201 -j DNAT --to-destination 192.168.1.20:22 | |
| | iptables -A FORWARD -p tcp --dport 22 -d 192.168.1.20 -j ACCEPT | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

Scenario 3: Multi-Tier Application Firewall

Section titled “Scenario 3: Multi-Tier Application Firewall”
Multi-Tier Application Architecture
+------------------------------------------------------------------+
| |
| +-------------+ +-------------+ +-------------+ |
| | Internet |----->| Load Balancer|---->| Web Servers | |
| | | | (DMZ) | | (DMZ) | |
| +-------------+ +-------------+ +-------------+ |
| | |
| v |
| +-------------+ |
| |App Servers | |
| | (Internal) | |
| +-------------+ |
| | |
| v |
| +-------------+ |
| | Database | |
| | (Internal) | |
| +-------------+ |
| |
| Firewall Rules: |
| +----------------------------------------------------------+ |
| | Load Balancer (DMZ): | |
| | - Allow 80/443 from Internet | |
| | - Allow SSH (22) from Admin IPs | |
| | | |
| | Web Servers (DMZ): | |
| | - Allow 80/443 from Load Balancer | |
| | - Allow SSH from Admin IPs | |
| | - Allow 8080 (app) from Web Servers | |
| | | |
| | App Servers (Internal): | |
| | - Allow 8080 from Web Servers | |
| | - Allow SSH from App Servers | |
| | - Allow 3306 (MySQL) from App Servers | |
| | | |
| | Database (Internal): | |
| | - Allow 3306 from App Servers only | |
| | - No direct access from Internet | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

Linux firewalls are essential for securing systems in production environments. Here’s a quick reference:

Firewall Tool Comparison
+------------------------------------------------------------------+
| |
| Tool | Best For | Complexity | Pros |
| ------------|--------------------|------------|---------------|
| iptables | Full control | High | Complete |
| | Legacy systems | | flexibility |
| ------------|--------------------|------------|---------------|
| nftables | Modern systems | Medium | Better |
| | Performance | | performance |
| ------------|--------------------|------------|---------------|
| firewalld | RHEL/CentOS | Low | Dynamic, |
| | Enterprise | | zone-based |
| ------------|--------------------|------------|---------------|
| ufw | Debian/Ubuntu | Very Low | Simple, |
| | Beginners | | human-readable|
| |
| Key Commands: |
| +----------------------------------------------------------+ |
| | iptables -L -n -v | List rules | |
| | iptables -A INPUT -p tcp --dport 80 | Allow HTTP | |
| | iptables -t nat -L -n | List NAT rules | |
| | nft list ruleset | List nft rules | |
| | firewall-cmd --list-all | List firewalld | |
| | ufw status | List UFW rules | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+