8.7. 示例:使用 nftables 脚本保护 LAN 和 DMZ
使用 RHEL 路由器上的 nftables
框架来编写和安装防火墙脚本,保护内部 LAN 中的网络客户端和 DMZ 中的 Web 服务器免受来自互联网和其他网络的未授权访问。
这个示例仅用于演示目的,并描述了具有特定要求的场景。
防火墙脚本高度依赖于网络基础架构和安全要求。当您为自己的环境编写脚本时,请使用此示例了解 nftables
防火墙的概念。
8.7.1. 网络状况
本例中的网络具有以下条件:
路由器连接到以下网络:
-
互联网通过接口
enp1s0
-
内部 LAN 通过接口
enp7s0
-
DMZ through
enp8s0
-
互联网通过接口
-
路由器的互联网接口分配了静态 IPv4 地址(
203.0.113.1
)和 IPv6 地址(2001:db8:a::1
)。 -
内部 LAN 中的客户端仅使用范围
10.0.0.0/24
中的专用 IPv4 地址。因此,来 LAN 到互联网的流量需要源网络地址转换(SNAT)。 -
内部 LAN 中的管理员 PC 使用 IP 地址
10.0.0.100
和10.0.0.200
。 -
DMZ 使用范围
198.51.100.0/24
和2001:db8:b::/56
的公共 IP 地址。 -
DMZ 中的 Web 服务器使用 IP 地址
198.51.100.5
和2001:db8:b::5
。 - 路由器充当 LAN 和 DMZ 中的主机的缓存 DNS 服务器。
8.7.2. 防火墙脚本的安全要求
以下是示例网络中 nftables
防火墙的要求:
路由器必须能够:
- 递归解析 DNS 查询。
- 在回环接口上执行所有连接。
内部 LAN 中的客户端必须能够:
- 查询在路由器上运行的缓存 DNS 服务器。
- 访问 DMZ 中的 HTTPS 服务器。
- 访问互联网上的任何 HTTPS 服务器。
- 管理员的 PC 必须能够使用 SSH 访问 DMZ 中的路由器和每个服务器。
DMZ 中的 Web 服务器必须能够:
- 查询在路由器上运行的缓存 DNS 服务器。
- 访问互联网上的 HTTPS 服务器以下载更新。
互联网上的主机必须能够:
- 访问 DMZ 中的 HTTPS 服务器。
另外,存在以下安全要求:
- 应丢弃未明确允许的连接尝试。
- 应记录丢弃的数据包。
8.7.3. 配置丢弃的数据包记录到文件中
默认情况下,systemd
会将内核消息(如 丢弃的数据包)记录到日志中。另外,您可以配置 rsyslog
服务,来将此类条目记录到单独的文件中。为确保日志文件不会无限增长,请配置轮转策略。
前提条件
-
rsyslog
软件包已安装。 -
rsyslog
服务正在运行。
流程
使用以下内容创建
/etc/rsyslog.d/nftables.conf
文件::msg, startswith, "nft drop" -/var/log/nftables.log & stop
使用这个配置,
rsyslog
服务会将数据包丢弃到/var/log/nftables.log
文件中,而不是/var/log/messages
。重启
rsyslog
服务:# systemctl restart rsyslog
使用以下内容创建
/etc/logrotate.d/nftables
文件,以便在大小超过 10 MB 时轮转/var/log/nftables.log
:/var/log/nftables.log { size +10M maxage 30 sharedscripts postrotate /usr/bin/systemctl kill -s HUP rsyslog.service >/dev/null 2>&1 || true endscript }
maxage 30
设置定义了logrotate
在下一次轮转操作期间删除超过 30 天的轮转日志。
其他资源
-
系统中
rsyslog.conf (5)
和logrotate (8)
手册页
8.7.4. 编写并激活 nftables 脚本
本例是在 RHEL 路由器上运行的 nftables
防火墙脚本,可保护内部 LAN 中的客户端以及 DMZ 中的 Web 服务器。有关示例中使用的防火墙的网络和要求的详情,请参阅 网络条件 和安全要求。
此 nftables
防火墙脚本仅用于演示目的。在符合您的环境和安全要求的情况下不要使用它。
前提条件
- 网络已配置,如 网络状况 中所述。
流程
使用以下内容创建
/etc/nftables/firewall.nft
脚本:# 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 } }
在
/etc/sysconfig/nftables.conf
文件中包括/etc/nftables/firewall.nft
脚本:include "/etc/nftables/firewall.nft"
启用 IPv4 转发:
# echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/95-IPv4-forwarding.conf # sysctl -p /etc/sysctl.d/95-IPv4-forwarding.conf
启用并启动
nftables
服务:# systemctl enable --now nftables
验证
可选:验证
nftables
规则集:# nft list ruleset ...
尝试执行防火墙阻止的访问。例如,尝试使用 DMZ 中的 SSH 访问路由器:
# ssh router.example.com ssh: connect to host router.example.com port 22: Network is unreachable
根据您的日志记录设置,搜索:
阻塞的数据包的
systemd
日志:# 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 ...
阻塞的数据包的
/var/log/nftables.log
文件: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 ...