Configure enterprise-grade network security with iptables and firewalld, implementing zone-based policies, advanced rules, and comprehensive logging for production infrastructure protection.
Prerequisites
- Root or sudo access
- Basic understanding of networking concepts
- Active network interface
What this solves
Enterprise networks require robust security policies to protect against threats, control traffic flow, and maintain compliance standards. This tutorial shows you how to implement comprehensive network security using both iptables (the traditional Linux firewall) and firewalld (the modern zone-based firewall manager) to create layered defense mechanisms for your infrastructure.
Step-by-step installation
Update system packages
Start by updating your system to ensure you have the latest security patches and package versions.
sudo apt update && sudo apt upgrade -y
Install iptables and firewalld
Install both firewall systems. Most distributions include iptables by default, but we'll ensure both tools are available.
sudo apt install -y iptables iptables-persistent firewalld
Configure firewalld as primary firewall
Enable firewalld and ensure it starts automatically. Firewalld will manage iptables rules dynamically.
sudo systemctl stop ufw 2>/dev/null || true
sudo systemctl disable ufw 2>/dev/null || true
sudo systemctl enable --now firewalld
sudo systemctl status firewalld
Configure zone-based security policies
Review default zones
Firewalld uses zones to define trust levels for network connections. Review available zones and their current configuration.
sudo firewall-cmd --get-zones
sudo firewall-cmd --get-default-zone
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --list-all
Create custom enterprise zones
Create specific zones for different network segments in your enterprise infrastructure.
sudo firewall-cmd --permanent --new-zone=dmz-servers
sudo firewall-cmd --permanent --new-zone=internal-services
sudo firewall-cmd --permanent --new-zone=management
sudo firewall-cmd --reload
Configure DMZ zone for web servers
Set up the DMZ zone for publicly accessible services with restricted access.
sudo firewall-cmd --permanent --zone=dmz-servers --set-description="DMZ zone for public-facing servers"
sudo firewall-cmd --permanent --zone=dmz-servers --add-service=http
sudo firewall-cmd --permanent --zone=dmz-servers --add-service=https
sudo firewall-cmd --permanent --zone=dmz-servers --add-service=ssh
sudo firewall-cmd --permanent --zone=dmz-servers --add-port=8080/tcp
sudo firewall-cmd --permanent --zone=dmz-servers --set-target=default
Configure internal services zone
Create a zone for internal services that should only be accessible from trusted networks.
sudo firewall-cmd --permanent --zone=internal-services --set-description="Internal services zone"
sudo firewall-cmd --permanent --zone=internal-services --add-source=10.0.0.0/8
sudo firewall-cmd --permanent --zone=internal-services --add-source=172.16.0.0/12
sudo firewall-cmd --permanent --zone=internal-services --add-source=192.168.0.0/16
sudo firewall-cmd --permanent --zone=internal-services --add-service=mysql
sudo firewall-cmd --permanent --zone=internal-services --add-service=postgresql
sudo firewall-cmd --permanent --zone=internal-services --add-port=6379/tcp
sudo firewall-cmd --permanent --zone=internal-services --add-port=9200/tcp
Configure management zone
Set up a highly restricted zone for management interfaces and administrative access.
sudo firewall-cmd --permanent --zone=management --set-description="Management and monitoring zone"
sudo firewall-cmd --permanent --zone=management --add-source=203.0.113.0/24
sudo firewall-cmd --permanent --zone=management --add-service=ssh
sudo firewall-cmd --permanent --zone=management --add-port=3000/tcp
sudo firewall-cmd --permanent --zone=management --add-port=9090/tcp
sudo firewall-cmd --permanent --zone=management --add-port=9093/tcp
sudo firewall-cmd --permanent --zone=management --set-target=DROP
Implement advanced firewall rules
Create rate limiting rules
Implement connection rate limiting to prevent DDoS attacks and brute force attempts.
sudo firewall-cmd --permanent --zone=dmz-servers --add-rich-rule='rule service name="ssh" accept limit value="5/m"'
sudo firewall-cmd --permanent --zone=dmz-servers --add-rich-rule='rule service name="http" accept limit value="100/s"'
sudo firewall-cmd --permanent --zone=dmz-servers --add-rich-rule='rule service name="https" accept limit value="100/s"'
Configure geo-blocking rules
Block traffic from specific countries or regions using IP ranges. This example blocks a range often associated with attacks.
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="198.51.100.0/24" reject'
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="203.0.113.0/24" accept'
Implement port knocking
Create a simple port knocking mechanism for enhanced SSH security.
sudo firewall-cmd --permanent --zone=public --remove-service=ssh
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule port port="12345" protocol="tcp" accept'
sudo firewall-cmd --permanent --add-service=ssh --zone=trusted
Configure application-specific rules
Create custom rules for specific applications and protocols commonly used in enterprise environments.
sudo firewall-cmd --permanent --zone=internal-services --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="5432" accept'
sudo firewall-cmd --permanent --zone=internal-services --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" service name="mysql" accept'
sudo firewall-cmd --permanent --zone=dmz-servers --add-rich-rule='rule family="ipv4" forward-port port="80" protocol="tcp" to-port="8080" to-addr="192.168.1.100"'
Configure comprehensive logging
Enable firewalld logging
Configure detailed logging for security monitoring and compliance requirements.
sudo firewall-cmd --set-log-denied=all
sudo firewall-cmd --permanent --set-log-denied=all
Configure rsyslog for firewall logs
Set up centralized logging to collect and organize firewall events.
# Firewall logging configuration
:msg,contains,"FINAL_REJECT:" /var/log/firewall-reject.log
:msg,contains,"FINAL_ACCEPT:" /var/log/firewall-accept.log
:msg,contains,"FINAL_DROP:" /var/log/firewall-drop.log
& stop
Configure log rotation
Set up automatic log rotation to prevent disk space issues while maintaining audit trails.
/var/log/firewall-*.log {
daily
missingok
rotate 365
compress
delaycompress
notifempty
create 640 root adm
postrotate
/bin/systemctl reload rsyslog > /dev/null 2>&1 || true
endscript
}
Enable detailed iptables logging
Configure custom iptables chains for granular logging of specific traffic patterns.
sudo iptables -N LOG_CHAIN
sudo iptables -A LOG_CHAIN -j LOG --log-prefix="IPTABLES-CUSTOM: " --log-level 4
sudo iptables -A LOG_CHAIN -j ACCEPT
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 22 -j LOG_CHAIN
Implement monitoring and alerting
Create firewall status monitoring script
Build a monitoring script to track firewall health and rule effectiveness.
#!/bin/bash
Firewall monitoring script
LOG_FILE="/var/log/firewall-monitor.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] Starting firewall health check" >> $LOG_FILE
Check firewalld status
if systemctl is-active --quiet firewalld; then
echo "[$DATE] Firewalld: ACTIVE" >> $LOG_FILE
else
echo "[$DATE] Firewalld: INACTIVE - ALERT" >> $LOG_FILE
logger -p daemon.err "Firewall monitoring: firewalld is not active"
fi
Count rejected connections in last hour
REJECT_COUNT=$(grep "$(date -d '1 hour ago' '+%b %d %H'):" /var/log/firewall-reject.log 2>/dev/null | wc -l)
echo "[$DATE] Rejected connections last hour: $REJECT_COUNT" >> $LOG_FILE
if [ $REJECT_COUNT -gt 1000 ]; then
logger -p daemon.warning "High number of rejected connections: $REJECT_COUNT"
fi
Check for configuration changes
CONFIG_HASH=$(sudo firewall-cmd --list-all-zones | sha256sum | cut -d' ' -f1)
echo "[$DATE] Configuration hash: $CONFIG_HASH" >> $LOG_FILE
Set up automated monitoring
Schedule regular monitoring and make the script executable.
sudo chmod +x /opt/firewall-monitor.sh
sudo chown root:root /opt/firewall-monitor.sh
echo "/15 * /opt/firewall-monitor.sh" | sudo crontab -
Configure fail2ban integration
Integrate fail2ban with your firewall configuration for automatic threat response. For comprehensive fail2ban setup, see our fail2ban configuration guide.
sudo apt install -y fail2ban
Configure fail2ban for firewalld
Set up fail2ban to work with firewalld for automated IP blocking.
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
banaction = firewallcmd-ipset
[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log
maxretry = 3
[nginx-req-limit]
enabled = true
filter = nginx-req-limit
action = firewallcmd-ipset[name=ReqLimit, port=http, protocol=tcp]
logpath = /var/log/nginx/error.log
findtime = 600
bantime = 7200
maxretry = 10
Apply all configurations
Reload all firewall rules and start monitoring services.
sudo firewall-cmd --reload
sudo systemctl restart rsyslog
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban
Verify your setup
Test your firewall configuration and verify all components are working correctly.
# Check firewalld status and zones
sudo firewall-cmd --state
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --list-all-zones
Verify logging is working
sudo tail -f /var/log/firewall-reject.log &
Try to connect to a blocked port from another machine
You should see entries in the log
Check fail2ban status
sudo fail2ban-client status
sudo fail2ban-client status sshd
Test monitoring script
sudo /opt/firewall-monitor.sh
cat /var/log/firewall-monitor.log
Verify iptables rules generated by firewalld
sudo iptables -L -n -v
sudo iptables -t nat -L -n -v
Advanced security hardening
Configure connection tracking
Enable advanced connection tracking for better security and performance.
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="0.0.0.0/0" forward-port port="80" protocol="tcp" to-port="8080" to-addr="192.168.1.100"'
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="0.0.0.0/0" service name="http" accept limit value="50/s"'
Implement network segmentation
Create rules for proper network segmentation between different zones.
sudo firewall-cmd --permanent --zone=internal-services --add-rich-rule='rule family="ipv4" source address="192.168.100.0/24" destination address="192.168.200.0/24" accept'
sudo firewall-cmd --permanent --zone=dmz-servers --add-rich-rule='rule family="ipv4" source address="192.168.100.0/24" destination address="10.0.0.0/8" reject'
Configure IPv6 security
Ensure IPv6 traffic is properly controlled alongside IPv4 rules.
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv6" source address="2001:db8::/32" service name="ssh" accept'
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv6" source address="::/0" service name="dhcpv6-client" accept'
Performance optimization
Optimize rule ordering
Order firewall rules for optimal performance, placing most common rules first.
# View current rule priorities
sudo firewall-cmd --list-rich-rules --zone=public
Add high-priority rules with specific priorities
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule priority="100" family="ipv4" source address="192.168.1.0/24" accept'
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule priority="200" service name="ssh" accept limit value="5/m"'
Configure connection limits
Set appropriate connection limits to prevent resource exhaustion.
# Network security and performance tuning
net.netfilter.nf_conntrack_max = 262144
net.netfilter.nf_conntrack_tcp_timeout_established = 7200
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120
net.netfilter.nf_conntrack_udp_timeout = 30
net.netfilter.nf_conntrack_generic_timeout = 600
Apply system optimizations
Load the network optimizations and verify they're applied.
sudo sysctl -p /etc/sysctl.d/99-network-security.conf
sudo sysctl net.netfilter.nf_conntrack_max
Backup and restore procedures
Create firewall backup script
Implement automated backup of firewall configurations for disaster recovery.
#!/bin/bash
BACKUP_DIR="/opt/firewall-backups"
DATE=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE="$BACKUP_DIR/firewall-backup-$DATE.tar.gz"
mkdir -p $BACKUP_DIR
Export firewalld configuration
sudo firewall-cmd --list-all-zones > $BACKUP_DIR/zones-$DATE.txt
sudo cp -r /etc/firewalld $BACKUP_DIR/firewalld-$DATE
Export iptables rules
sudo iptables-save > $BACKUP_DIR/iptables-$DATE.rules
sudo ip6tables-save > $BACKUP_DIR/ip6tables-$DATE.rules
Create compressed backup
cd $BACKUP_DIR
sudo tar -czf $BACKUP_FILE zones-$DATE.txt firewalld-$DATE iptables-$DATE.rules ip6tables-$DATE.rules
Clean up temporary files
sudo rm -rf zones-$DATE.txt firewalld-$DATE iptables-$DATE.rules ip6tables-$DATE.rules
Keep only last 30 backups
find $BACKUP_DIR -name "firewall-backup-*.tar.gz" -type f -mtime +30 -delete
echo "Backup created: $BACKUP_FILE"
Schedule automated backups
Set up daily backups of your firewall configuration.
sudo chmod +x /opt/firewall-backup.sh
sudo mkdir -p /opt/firewall-backups
echo "0 2 * /opt/firewall-backup.sh" | sudo crontab -
Integration with monitoring systems
Configure Prometheus metrics export
Set up metrics collection for integration with monitoring systems like those covered in our Prometheus and Grafana monitoring guide.
#!/bin/bash
Export firewall metrics for Prometheus
METRICS_FILE="/var/lib/prometheus/node-exporter/firewall.prom"
mkdir -p $(dirname $METRICS_FILE)
Count active connections
ACTIVE_CONNECTIONS=$(ss -ant | grep ESTABLISHED | wc -l)
echo "firewall_active_connections $ACTIVE_CONNECTIONS" > $METRICS_FILE
Count firewall rules
FIREWALL_RULES=$(sudo firewall-cmd --list-all-zones | grep -c "services:\|ports:\|rich rules:")
echo "firewall_total_rules $FIREWALL_RULES" >> $METRICS_FILE
Count blocked IPs from fail2ban
BLOCKED_IPS=$(sudo fail2ban-client status sshd 2>/dev/null | grep "Currently banned:" | awk '{print $NF}' || echo 0)
echo "firewall_blocked_ips $BLOCKED_IPS" >> $METRICS_FILE
Enable metrics collection
Schedule metrics collection for monitoring integration.
sudo chmod +x /opt/firewall-metrics.sh
echo " * /opt/firewall-metrics.sh" | sudo crontab -
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Services not accessible | Firewall blocking required ports | sudo firewall-cmd --list-all and add missing services/ports |
| Firewalld won't start | Conflicting with iptables service | sudo systemctl stop iptables && sudo systemctl disable iptables |
| Rules not persisting | Missing --permanent flag | Re-add rules with --permanent and run firewall-cmd --reload |
| High CPU usage | Too many connection tracking entries | Increase net.netfilter.nf_conntrack_max in sysctl |
| Logs not appearing | rsyslog not configured properly | Check /etc/rsyslog.d/10-firewall.conf and restart rsyslog |
| Zone assignment issues | Interface not assigned to correct zone | sudo firewall-cmd --change-interface=eth0 --zone=dmz-servers |
| Rich rules not working | Syntax errors in rule definition | Validate syntax with firewall-cmd --check-config |
firewall-cmd --set-default-zone=trusted, test your application, then return to proper security with firewall-cmd --set-default-zone=public and configure specific rules.Next steps
- Implement comprehensive Linux security hardening with CIS benchmarks
- Configure NGINX rate limiting and DDoS protection
- Set up centralized logging for security events
- Configure enterprise firewall automation with Ansible
- Implement network intrusion detection with Suricata
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Configuration
MANAGEMENT_NETWORK="${1:-203.0.113.0/24}"
# Usage message
usage() {
echo "Usage: $0 [management_network]"
echo " management_network: CIDR block for management access (default: 203.0.113.0/24)"
exit 1
}
# Logging functions
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Cleanup function for rollback
cleanup() {
log_error "Installation failed. Performing cleanup..."
systemctl stop firewalld 2>/dev/null || true
systemctl disable firewalld 2>/dev/null || true
if [[ "$PKG_MGR" == "apt" ]]; then
systemctl enable --now ufw 2>/dev/null || true
fi
}
# Set error trap
trap cleanup ERR
# Validate management network
if [[ ! "$MANAGEMENT_NETWORK" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then
log_error "Invalid management network format: $MANAGEMENT_NETWORK"
usage
fi
# Check for root privileges
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root"
exit 1
fi
# Auto-detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update && apt upgrade -y"
IPTABLES_PKG="iptables iptables-persistent"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
IPTABLES_PKG="iptables-services"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
IPTABLES_PKG="iptables-services"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect distribution"
exit 1
fi
log_info "Detected distribution: $ID"
log_info "Management network: $MANAGEMENT_NETWORK"
# Step 1: Update system packages
echo "[1/8] Updating system packages..."
$PKG_UPDATE
# Step 2: Install firewall packages
echo "[2/8] Installing iptables and firewalld..."
$PKG_INSTALL $IPTABLES_PKG firewalld
# Step 3: Configure firewalld as primary firewall
echo "[3/8] Configuring firewalld as primary firewall..."
if [[ "$PKG_MGR" == "apt" ]]; then
systemctl stop ufw 2>/dev/null || true
systemctl disable ufw 2>/dev/null || true
fi
systemctl enable --now firewalld
sleep 2
# Step 4: Review default zones
echo "[4/8] Reviewing default zones..."
firewall-cmd --get-zones
firewall-cmd --get-default-zone
firewall-cmd --get-active-zones
# Step 5: Create custom enterprise zones
echo "[5/8] Creating custom enterprise zones..."
firewall-cmd --permanent --new-zone=dmz-servers
firewall-cmd --permanent --new-zone=internal-services
firewall-cmd --permanent --new-zone=management
firewall-cmd --reload
# Step 6: Configure DMZ zone for web servers
echo "[6/8] Configuring DMZ zone..."
firewall-cmd --permanent --zone=dmz-servers --set-description="DMZ zone for public-facing servers"
firewall-cmd --permanent --zone=dmz-servers --add-service=http
firewall-cmd --permanent --zone=dmz-servers --add-service=https
firewall-cmd --permanent --zone=dmz-servers --add-service=ssh
firewall-cmd --permanent --zone=dmz-servers --add-port=8080/tcp
firewall-cmd --permanent --zone=dmz-servers --set-target=default
# Configure internal services zone
log_info "Configuring internal services zone..."
firewall-cmd --permanent --zone=internal-services --set-description="Internal services zone"
firewall-cmd --permanent --zone=internal-services --add-source=10.0.0.0/8
firewall-cmd --permanent --zone=internal-services --add-source=172.16.0.0/12
firewall-cmd --permanent --zone=internal-services --add-source=192.168.0.0/16
firewall-cmd --permanent --zone=internal-services --add-service=mysql
firewall-cmd --permanent --zone=internal-services --add-service=postgresql
firewall-cmd --permanent --zone=internal-services --add-port=6379/tcp
firewall-cmd --permanent --zone=internal-services --add-port=9200/tcp
# Step 7: Configure management zone
echo "[7/8] Configuring management zone..."
firewall-cmd --permanent --zone=management --set-description="Management and monitoring zone"
firewall-cmd --permanent --zone=management --add-source="$MANAGEMENT_NETWORK"
firewall-cmd --permanent --zone=management --add-service=ssh
firewall-cmd --permanent --zone=management --add-port=3000/tcp
firewall-cmd --permanent --zone=management --add-port=9090/tcp
firewall-cmd --permanent --zone=management --add-port=9093/tcp
firewall-cmd --permanent --zone=management --set-target=DROP
# Create rich rules for rate limiting
log_info "Implementing rate limiting rules..."
firewall-cmd --permanent --zone=dmz-servers --add-rich-rule='rule service name="ssh" accept limit value="10/m"'
firewall-cmd --permanent --zone=dmz-servers --add-rich-rule='rule service name="http" accept limit value="100/s"'
firewall-cmd --permanent --zone=dmz-servers --add-rich-rule='rule service name="https" accept limit value="100/s"'
# Configure logging for dropped packets
firewall-cmd --permanent --set-log-denied=all
# Apply configuration
firewall-cmd --reload
# Step 8: Verification and status
echo "[8/8] Verifying firewall configuration..."
log_info "Firewalld status:"
systemctl status firewalld --no-pager -l
log_info "Active zones:"
firewall-cmd --get-active-zones
log_info "Zone configurations:"
for zone in dmz-servers internal-services management; do
echo "=== Zone: $zone ==="
firewall-cmd --zone="$zone" --list-all
echo
done
log_info "Rate limiting rules:"
firewall-cmd --zone=dmz-servers --list-rich-rules
# Create backup script
cat > /usr/local/bin/firewall-backup << 'EOF'
#!/bin/bash
BACKUP_DIR="/etc/firewalld/backup"
mkdir -p "$BACKUP_DIR"
cp -r /etc/firewalld/zones "$BACKUP_DIR/zones-$(date +%Y%m%d-%H%M%S)"
firewall-cmd --list-all-zones > "$BACKUP_DIR/config-$(date +%Y%m%d-%H%M%S).txt"
EOF
chmod 755 /usr/local/bin/firewall-backup
chown root:root /usr/local/bin/firewall-backup
# Create restore point
/usr/local/bin/firewall-backup
# Disable error trap on successful completion
trap - ERR
log_info "Enterprise firewall configuration completed successfully!"
log_info "Management network configured: $MANAGEMENT_NETWORK"
log_info "Backup script created at: /usr/local/bin/firewall-backup"
log_warn "Ensure your current connection matches the management network or you may lose access!"
Review the script before running. Execute with: bash install.sh