Why NFTables Over iptables?
NFTables was introduced in Linux kernel 3.13 as the successor to the iptables/ip6tables/arptables/ebtables framework. While iptables served the community well for over two decades, NFTables offers significant improvements that make it the clear choice for modern deployments:
- Unified framework, A single tool handles IPv4, IPv6, ARP, and bridge filtering, eliminating the need for separate utilities.
- Better syntax, More readable and consistent rule syntax that reduces configuration errors.
- Atomic rule updates, Entire rulesets can be replaced atomically, preventing the brief vulnerability window that iptables rule-by-rule updates create.
- Native sets and maps, Built-in data structures for IP sets, port ranges, and dictionary-style mappings without external tools like ipset.
- Improved performance, More efficient packet classification through a pseudo-state machine approach.
Building a Production NFTables Ruleset
A well-structured NFTables configuration follows the principle of default-deny: block everything, then explicitly allow only the traffic your server needs. Here is a production-grade ruleset for a typical web server:
#!/usr/sbin/nft -f
# NFTables production ruleset for web server hardening
# Flush existing rules for clean slate
flush ruleset
table inet filter {
# Define allowed IP sets
set admin_ips {
type ipv4_addr
elements = { 10.0.1.50, 192.168.1.100 }
}
set blocked_countries {
type ipv4_addr
flags interval
}
chain input {
type filter hook input priority 0; policy drop;
# Allow established and related connections
ct state established,related accept
# Drop invalid packets
ct state invalid drop
# Allow loopback
iif "lo" accept
# ICMP rate limiting (allow ping but prevent flood)
ip protocol icmp icmp type echo-request \
limit rate 5/second burst 10 packets accept
# SSH - restricted to admin IPs only
tcp dport 22 ip saddr @admin_ips accept
# HTTP and HTTPS - open to world
tcp dport { 80, 443 } accept
# DNS (if running local resolver)
udp dport 53 accept
tcp dport 53 accept
# Log and drop everything else
log prefix "NFT-DROP: " limit rate 5/minute
counter drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
SSH Hardening
SSH is the primary remote access vector and the most attacked service on any public-facing Linux server. Beyond firewall restrictions, the SSH daemon itself must be hardened:
# /etc/ssh/sshd_config hardening
Port 2222 # Non-standard port (not security, but reduces noise)
PermitRootLogin no # Force sudo escalation
PasswordAuthentication no # Key-based auth only
PubkeyAuthentication yes
MaxAuthTries 3 # Lock out after 3 failed attempts
ClientAliveInterval 300 # Disconnect idle sessions after 5 min
ClientAliveCountMax 2
AllowUsers deploy admin # Whitelist specific users
Protocol 2 # Disable legacy SSHv1
Key-based authentication eliminates the entire class of brute-force password attacks. Combined with fail2ban or SSHGuard for automated IP blocking, this configuration makes SSH compromise significantly more difficult.
Kernel Security Parameters
The Linux kernel exposes numerous tunable parameters through sysctl that significantly impact security posture. Essential hardening parameters include:
# /etc/sysctl.d/99-security.conf
# Prevent IP spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Disable source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# Disable ICMP redirects (prevent MITM)
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
# Enable SYN flood protection
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
# Disable IP forwarding (unless routing)
net.ipv4.ip_forward = 0
# Log suspicious packets
net.ipv4.conf.all.log_martians = 1
Filesystem and Permission Hardening
File permissions are a fundamental security layer that is often overlooked. Critical steps include:
- Restrict /tmp execution, Mount /tmp with noexec,nosuid,nodev options to prevent malicious script execution from world-writable directories.
- Secure cron directories, Ensure /etc/crontab and /etc/cron.d/ are owned by root with 600 permissions.
- Remove SUID/SGID binaries, Audit and remove unnecessary SUID bits that could enable privilege escalation.
- Enable filesystem auditing, Use auditd to monitor access to sensitive files like /etc/passwd, /etc/shadow, and SSH keys.
Automated Security Updates
Unpatched vulnerabilities remain the most exploited attack vector. Configure unattended upgrades for security patches:
# Ubuntu/Debian
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
# Verify configuration
cat /etc/apt/apt.conf.d/50unattended-upgrades
# Ensure security updates are enabled:
# "${distro_id}:${distro_codename}-security";
Monitoring and Alerting
Hardening is not a one-time activity, it requires continuous monitoring. Essential monitoring components include:
- Log aggregation, Centralize logs with rsyslog or journald forwarding to detect suspicious patterns across services.
- File integrity monitoring, Tools like AIDE or Tripwire detect unauthorized modifications to system files and binaries.
- Process monitoring, Track running processes and network connections to identify unauthorized services or backdoors.
- NFTables logging, The log prefix in our ruleset feeds dropped packet information to syslog for analysis and alerting.
Conclusion
Server hardening is a layered discipline. NFTables provides the network-level foundation, but true security requires defense in depth, combining firewall rules with SSH hardening, kernel tuning, filesystem controls, automated patching, and continuous monitoring. No single measure is sufficient; together, they create a resilient security posture that significantly raises the cost of compromise for attackers.