Chapter 16. Example: Protecting a LAN and DMZ using an nftables script
Use the nftables
framework on a RHEL router to write and install a firewall script that protects the network clients in an internal LAN and a web server in a DMZ from unauthorized access from the internet and from other networks.
This example is only for demonstration purposes and describes a scenario with specific requirements.
Firewall scripts highly depend on the network infrastructure and security requirements. Use this example to learn the concepts of nftables
firewalls when you write scripts for your own environment.
16.1. Network conditions
The network in this example has the following conditions:
The router is connected to the following networks:
-
The internet through interface
enp1s0
-
The internal LAN through interface
enp7s0
-
The DMZ through
enp8s0
-
The internet through interface
-
The internet interface of the router has both a static IPv4 address (
203.0.113.1
) and IPv6 address (2001:db8:a::1
) assigned. -
The clients in the internal LAN use only private IPv4 addresses from the range
10.0.0.0/24
. Consequently, traffic from the LAN to the internet requires source network address translation (SNAT). -
The administrator PCs in the internal LAN use the IP addresses
10.0.0.100
and10.0.0.200
. -
The DMZ uses public IP addresses from the ranges
198.51.100.0/24
and2001:db8:b::/56
. -
The web server in the DMZ uses the IP addresses
198.51.100.5
and2001:db8:b::5
. - The router acts as a caching DNS server for hosts in the LAN and DMZ.
16.2. Security requirements to the firewall script
The following are the requirements to the nftables
firewall in the example network:
The router must be able to:
- Recursively resolve DNS queries.
- Perform all connections on the loopback interface.
Clients in the internal LAN must be able to:
- Query the caching DNS server running on the router.
- Access the HTTPS server in the DMZ.
- Access any HTTPS server on the internet.
- The PCs of the administrators must be able to access the router and every server in the DMZ using SSH.
The web server in the DMZ must be able to:
- Query the caching DNS server running on the router.
- Access HTTPS servers on the internet to download updates.
Hosts on the internet must be able to:
- Access the HTTPS servers in the DMZ.
Additionally, the following security requirements exists:
- Connection attempts that are not explicitly allowed should be dropped.
- Dropped packets should be logged.
16.3. Configuring logging of dropped packets to a file
By default, systemd
logs kernel messages, such as for dropped packets, to the journal. Additionally, you can configure the rsyslog
service to log such entries to a separate file. To ensure that the log file does not grow infinitely, configure a rotation policy.
Prerequisites
-
The
rsyslog
package is installed. -
The
rsyslog
service is running.
Procedure
Create the
/etc/rsyslog.d/nftables.conf
file with the following content::msg, startswith, "nft drop" -/var/log/nftables.log & stop
:msg, startswith, "nft drop" -/var/log/nftables.log & stop
Copy to Clipboard Copied! Using this configuration, the
rsyslog
service logs dropped packets to the/var/log/nftables.log
file instead of/var/log/messages
.Restart the
rsyslog
service:systemctl restart rsyslog
# systemctl restart rsyslog
Copy to Clipboard Copied! Create the
/etc/logrotate.d/nftables
file with the following content to rotate/var/log/nftables.log
if the size exceeds 10 MB:/var/log/nftables.log { size +10M maxage 30 sharedscripts postrotate /usr/bin/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true endscript }
/var/log/nftables.log { size +10M maxage 30 sharedscripts postrotate /usr/bin/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true endscript }
Copy to Clipboard Copied! The
maxage 30
setting defines thatlogrotate
removes rotated logs older than 30 days during the next rotation operation.
16.4. Writing and activating the nftables script
This example is an nftables
firewall script that runs on a RHEL router and protects the clients in an internal LAN and a web server in a DMZ. For details about the network and the requirements for the firewall used in the example, see Network conditions and Security requirements to the firewall script.
This nftables
firewall script is only for demonstration purposes. Do not use it without adapting it to your environments and security requirements.
Prerequisites
- The network is configured as described in Network conditions.
Procedure
Create the
/etc/nftables/firewall.nft
script with the following content:Remove all rules Table for both IPv4 and IPv6 rules
# Remove all rules flush ruleset # Table for both IPv4 and IPv6 rules table inet nftables_svc { # Define variables for the interface name define INET_DEV = enp1s0 define LAN_DEV = enp7s0 define DMZ_DEV = enp8s0 # Set with the IPv4 addresses of admin PCs set admin_pc_ipv4 { type ipv4_addr elements = { 10.0.0.100, 10.0.0.200 } } # Chain for incoming trafic. Default policy: drop chain INPUT { type filter hook input priority filter policy drop # Accept packets in established and related state, drop invalid packets ct state vmap { established:accept, related:accept, invalid:drop } # Accept incoming traffic on loopback interface iifname lo accept # Allow request from LAN and DMZ to local DNS server iifname { $LAN_DEV, $DMZ_DEV } meta l4proto { tcp, udp } th dport 53 accept # Allow admins PCs to access the router using SSH iifname $LAN_DEV ip saddr @admin_pc_ipv4 tcp dport 22 accept # Last action: Log blocked packets # (packets that were not accepted in previous rules in this chain) log prefix "nft drop IN : " } # Chain for outgoing traffic. Default policy: drop chain OUTPUT { type filter hook output priority filter policy drop # Accept packets in established and related state, drop invalid packets ct state vmap { established:accept, related:accept, invalid:drop } # Accept outgoing traffic on loopback interface oifname lo accept # Allow local DNS server to recursively resolve queries oifname $INET_DEV meta l4proto { tcp, udp } th dport 53 accept # Last action: Log blocked packets log prefix "nft drop OUT: " } # Chain for forwarding traffic. Default policy: drop chain FORWARD { type filter hook forward priority filter policy drop # Accept packets in established and related state, drop invalid packets ct state vmap { established:accept, related:accept, invalid:drop } # IPv4 access from LAN and internet to the HTTPS server in the DMZ iifname { $LAN_DEV, $INET_DEV } oifname $DMZ_DEV ip daddr 198.51.100.5 tcp dport 443 accept # IPv6 access from internet to the HTTPS server in the DMZ iifname $INET_DEV oifname $DMZ_DEV ip6 daddr 2001:db8:b::5 tcp dport 443 accept # Access from LAN and DMZ to HTTPS servers on the internet iifname { $LAN_DEV, $DMZ_DEV } oifname $INET_DEV tcp dport 443 accept # Last action: Log blocked packets log prefix "nft drop FWD: " } # Postrouting chain to handle SNAT chain postrouting { type nat hook postrouting priority srcnat; policy accept; # SNAT for IPv4 traffic from LAN to internet iifname $LAN_DEV oifname $INET_DEV snat ip to 203.0.113.1 } }
Copy to Clipboard Copied! Include the
/etc/nftables/firewall.nft
script in the/etc/sysconfig/nftables.conf
file:include "/etc/nftables/firewall.nft"
include "/etc/nftables/firewall.nft"
Copy to Clipboard Copied! Enable IPv4 forwarding:
echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/95-IPv4-forwarding.conf sysctl -p /etc/sysctl.d/95-IPv4-forwarding.conf
# echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/95-IPv4-forwarding.conf # sysctl -p /etc/sysctl.d/95-IPv4-forwarding.conf
Copy to Clipboard Copied! Enable and start the
nftables
service:systemctl enable --now nftables
# systemctl enable --now nftables
Copy to Clipboard Copied!
Verification
Optional: Verify the
nftables
rule set:nft list ruleset
# nft list ruleset ...
Copy to Clipboard Copied! Try to perform an access that the firewall prevents. For example, try to access the router using SSH from the DMZ:
ssh router.example.com
# ssh router.example.com ssh: connect to host router.example.com port 22: Network is unreachable
Copy to Clipboard Copied! Depending on your logging settings, search:
The
systemd
journal for the blocked packets:journalctl -k -g "nft drop"
# journalctl -k -g "nft drop" Oct 14 17:27:18 router kernel: nft drop IN : IN=enp8s0 OUT= MAC=... SRC=198.51.100.5 DST=198.51.100.1 ... PROTO=TCP SPT=40464 DPT=22 ... SYN ...
Copy to Clipboard Copied! The
/var/log/nftables.log
file for the blocked packets:Oct 14 17:27:18 router kernel: nft drop IN : IN=enp8s0 OUT= MAC=... SRC=198.51.100.5 DST=198.51.100.1 ... PROTO=TCP SPT=40464 DPT=22 ... SYN ...
Oct 14 17:27:18 router kernel: nft drop IN : IN=enp8s0 OUT= MAC=... SRC=198.51.100.5 DST=198.51.100.1 ... PROTO=TCP SPT=40464 DPT=22 ... SYN ...
Copy to Clipboard Copied!