找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2297

积分

0

好友

331

主题
发表于 18 小时前 | 查看: 2| 回复: 0

概述

在Linux系统管理的世界里,防火墙工具的选型是一个经久不衰的话题。自2015年RHEL 7引入firewalld至今,许多团队仍在iptables与firewalld之间摇摆不定。经验丰富的运维工程师可能固守iptables,认为它更直接可靠;而新入行的工程师则可能更倾向于firewalld的易用性,但在面对复杂需求时又会感到棘手。

经过从几台到上万台服务器的管理实践,踩过无数坑之后,我们有必要系统性地梳理这两个工具的异同,并提供一个清晰、可落地的选型标准。

为什么要写这篇文章

尽管已是2025年,这个话题的现实意义并未减弱。就在上个月,我们还在处理一个客户生产环境中因iptables规则冲突导致的服务中断,他们的系统仍运行在CentOS 7上。另一方面,许多使用Rocky Linux 9的团队,对firewalld的理解也仅停留在表面,无法发挥其全部能力。

本文旨在达成以下几个目标:

  • 让你真正理解iptables与firewalld的本质区别。
  • 提供一套清晰的、可操作的选型标准。
  • 通过丰富的实战案例,提供即拿即用的配置方案。
  • 帮你避开那些常见的陷阱和误区。

本文适合谁看

  • 刚入行的运维工程师,希望系统学习Linux防火墙。
  • 有多年iptables使用经验,希望了解firewalld的老手。
  • 正在规划系统升级,需要决策防火墙方案的架构师。
  • 在面试中需要深入回答此问题的求职者。

第一章:从底层理解两者的本质

1.1 先搞清楚netfilter是什么

理解整个Linux防火墙体系的关键,在于分清iptablesfirewalldnetfilter的关系。

netfilter是Linux内核中的一个框架,它提供了一系列“钩子”(hooks),允许内核模块在网络数据包流经协议栈的不同阶段进行干预处理。这些关键的钩子点包括:

PREROUTING  → 数据包刚进入网络层,尚未进行路由决策
INPUT       → 数据包的目标是本机
FORWARD     → 数据包需要被转发到其他机器
OUTPUT      → 由本机产生的数据包
POSTROUTING → 数据包即将离开本机

iptables和firewalld本身并非防火墙,它们只是用于操作netfilter的用户空间工具。真正执行包过滤、地址转换等任务的是内核中的netfilter模块。这就好比你可以用Vim或VSCode编写代码,但最终执行代码的是编译器和CPU。

1.2 iptables的工作原理

iptables直接通过系统调用与内核的netfilter交互,将规则写入内核空间的表中。它的核心概念是表(table)链(chain)

主要的四张表及其处理优先级如下:

raw → mangle → nat → filter

每张表包含不同的链:

filter表:INPUT, FORWARD, OUTPUT
nat表:PREROUTING, OUTPUT, POSTROUTING
mangle表:所有五个链
raw表:PREROUTING, OUTPUT

一条典型的iptables规则如下:

iptables -t filter -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT

参数解析:

  • -t filter:指定操作filter表。
  • -A INPUT:在INPUT链的末尾追加规则。
  • -p tcp:匹配TCP协议。
  • --dport 22:目标端口为22(SSH)。
  • -s 192.168.1.0/24:源IP地址段。
  • -j ACCEPT:执行允许通过的动作。

1.3 firewalld的架构设计

firewalld是Red Hat于2011年开发的动态防火墙管理工具。它在iptables(或其继任者nftables)之上构建了一层抽象,引入了区域(zone) 这一核心概念。

其架构层次如下:

用户层:firewall-cmd / firewall-config
    ↓
服务层:firewalld daemon (通过D-Bus接口通信)
    ↓
后端层:iptables / nftables / direct规则
    ↓
内核层:netfilter

一个重要的技术演进是:从RHEL 8/CentOS 8开始,firewalld默认使用nftables作为其后端,而非iptables。nftables作为iptables的继任者,语法更简洁,性能更优,尤其是在处理大量复杂规则时。

查看当前firewalld使用的后端:

grep FirewallBackend /etc/firewalld/firewalld.conf
# 输出示例:FirewallBackend=nftables

1.4 2025年的技术现状

截至2025年,主流Linux发行版的防火墙默认配置如下:

发行版 默认防火墙工具 后端
RHEL 9 / Rocky 9 / AlmaLinux 9 firewalld nftables
Ubuntu 24.04 LTS ufw (基于iptables) iptables
Debian 12 nftables原生 nftables
openSUSE Leap 15.6 firewalld nftables

可以看出,nftables已成为事实上的新标准。但由于巨大的历史兼容性包袱,iptables的兼容层仍将长期存在。理解底层的网络与系统原理,对于选择和管理上层的防火墙工具至关重要。

第二章:iptables深度实战

2.1 基础配置详解

让我们从一个干净的环境开始。以下操作在Rocky Linux 9上执行,首先需要切换到iptables后端:

# 安装iptables服务
dnf install iptables-services -y

# 停用并禁用firewalld
systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld

# 启用iptables服务
systemctl enable iptables
systemctl start iptables

查看当前生效的规则:

iptables -L -n -v --line-numbers

输出示例:

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

2.2 构建一套生产级规则

下面是一套经过多年生产环境检验的基础防火墙规则模板,遵循“默认拒绝”的安全原则:

#!/bin/bash
# iptables-setup.sh
# 生产环境基础防火墙规则

# 清空现有规则、自定义链和计数器
iptables -F
iptables -X
iptables -Z

# 设置默认策略(INPUT和FORWARD默认拒绝,OUTPUT默认允许)
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# 允许回环接口的所有流量(本地进程间通信)
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# 允许已建立的和相关的连接(确保应答包能回来)
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 允许ICMP (ping),但限制速率防止洪水攻击
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 4 -j ACCEPT

# SSH访问控制 - 只允许特定的运维网段
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -s 192.168.0.0/16 -j ACCEPT

# Web服务端口
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 防止SYN洪水攻击
iptables -A INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPT

# 丢弃无效状态的数据包
iptables -A INPUT -m state --state INVALID -j DROP

# 记录被拒绝的数据包(便于后期排查问题)
iptables -A INPUT -j LOG --log-prefix “IPTables-Dropped: “ --log-level 4

# 保存规则(RHEL/CentOS系列)
service iptables save

2.3 高级场景:多端口和IP集合

管理大量IP或端口时,逐条添加规则效率低下。此时应使用multiportipset模块。

multiport示例:

# 一次性允许多个离散端口
iptables -A INPUT -p tcp -m multiport --dports 80,443,8080,8443 -j ACCEPT

# 允许一个连续的端口范围
iptables -A INPUT -p tcp --dport 3000:3999 -j ACCEPT

ipset示例:
ipset用于管理IP地址集合,当IP数量庞大时,其匹配效率远高于逐条规则匹配。

# 安装ipset
dnf install ipset -y

# 创建不同类型的IP集合
ipset create whitelist hash:ip
ipset create blacklist hash:ip
ipset create office_network hash:net

# 向集合中添加IP/网段
ipset add whitelist 1.2.3.4
ipset add whitelist 5.6.7.8
ipset add blacklist 10.20.30.40
ipset add office_network 192.168.1.0/24
ipset add office_network 192.168.2.0/24

# 在iptables规则中引用ipset
iptables -A INPUT -m set --match-set whitelist src -j ACCEPT
iptables -A INPUT -m set --match-set blacklist src -j DROP
iptables -A INPUT -p tcp --dport 22 -m set --match-set office_network src -j ACCEPT

# 保存ipset配置
ipset save > /etc/ipset.conf

# 创建systemd服务实现开机自动加载
cat > /etc/systemd/system/ipset-restore.service << ‘EOF’
[Unit]
Description=Restore ipset rules
Before=iptables.service

[Service]
Type=oneshot
ExecStart=/usr/sbin/ipset restore -f /etc/ipset.conf
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

systemctl enable ipset-restore

2.4 NAT和端口转发

NAT和端口转发是网关/路由器角色的核心功能,配置需谨慎。

场景一:SNAT(源地址转换)
内网服务器通过网关访问外网:

# 开启内核的IP转发功能
echo 1 > /proc/sys/net/ipv4/ip_forward
echo “net.ipv4.ip_forward = 1” >> /etc/sysctl.conf

# SNAT规则(使用MASQUERADE,适用于动态IP或单出口)
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

# SNAT规则(使用SNAT,适用于固定公网IP,效率更高)
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 203.0.113.10

场景二:DNAT(目标地址转换)
将公网IP的请求转发到内网服务器:

# 将公网IP 203.0.113.10的80端口请求转发到内网192.168.1.100的80端口
iptables -t nat -A PREROUTING -d 203.0.113.10 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.100:80

# 在FORWARD链中放行转发的流量
iptables -A FORWARD -d 192.168.1.100 -p tcp --dport 80 -j ACCEPT
iptables -A FORWARD -s 192.168.1.100 -p tcp --sport 80 -j ACCEPT

场景三:本机端口转发
将访问本机某端口的请求重定向到另一个端口:

iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80

2.5 iptables规则持久化

规则持久化是必须解决的问题,不同发行版方法不同。

CentOS/RHEL系列:

# 保存当前内存中的规则到配置文件
service iptables save
# 规则默认保存在 /etc/sysconfig/iptables

# 或手动保存
iptables-save > /etc/sysconfig/iptables

Debian/Ubuntu系列:

# 安装持久化工具
apt install iptables-persistent -y

# 保存当前规则
netfilter-persistent save
# IPv4规则保存在 /etc/iptables/rules.v4
# IPv6规则保存在 /etc/iptables/rules.v6

通用脚本方法:

# 将规则恢复脚本加入开机启动(如/etc/rc.local)
cat > /etc/rc.local << ‘EOF’
#!/bin/bash
/path/to/your/iptables-setup.sh
exit 0
EOF
chmod +x /etc/rc.local

第三章:firewalld深度实战

3.1 核心概念:Zone(区域)

Zone是firewalld最核心的概念。每个zone定义了一整套信任级别和规则集,网络接口或源IP地址可以被绑定到不同的zone。

系统预定义的zone及其用途:

drop        - 丢弃所有传入数据包,不发出任何拒绝响应。
block       - 拒绝所有传入连接,返回ICMP拒绝信息。
public      - 公共区域,不信任的网络,只允许选定的入站连接(默认zone)。
external    - 外部网络,启用NAT伪装,适用于网关。
dmz         - 非军事区,仅允许有限的入站连接。
work        - 工作网络,信任网络中的大部分机器。
home        - 家庭网络,信任网络中的大部分机器。
internal    - 内部网络,信任度与work类似。
trusted     - 信任所有网络连接。

查看和管理zone:

# 查看所有可用zone
firewall-cmd --get-zones

# 查看默认zone
firewall-cmd --get-default-zone
# 输出:public

# 查看某个zone的详细配置
firewall-cmd --zone=public --list-all

输出示例:

public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens192
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  protocols:
  forward: yes
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

3.2 服务管理

firewalld通过预定义的“服务”来管理常见应用程序的端口,这比记忆端口号更为直观和安全。

查看可用的服务:

firewall-cmd --get-services

添加和删除服务:

# 临时添加(重启firewalld或系统后失效)
firewall-cmd --add-service=http
firewall-cmd --add-service=https

# 永久添加(--permanent参数),添加后需重载配置
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

# 永久删除服务
firewall-cmd --permanent --remove-service=ssh
firewall-cmd --reload

自定义服务:
当应用使用非标准端口时,可以创建自定义服务。

# 以已有服务为模板创建自定义服务文件
cp /usr/lib/firewalld/services/http.xml /etc/firewalld/services/myapp.xml

# 编辑服务定义
cat > /etc/firewalld/services/myapp.xml << ‘EOF’
<?xml version=”1.0” encoding=”utf-8”?>
<service>
  <short>MyApp</short>
  <description>My Application Service on port 9000</description>
  <port protocol=”tcp” port=”9000”/>
</service>
EOF

# 重新加载服务定义并添加
firewall-cmd --reload
firewall-cmd --permanent --add-service=myapp
firewall-cmd --reload

3.3 端口管理

对于没有预定义服务的端口,可以直接进行管理。

# 永久开放单个端口
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --permanent --add-port=53/udp

# 永久开放一个端口范围
firewall-cmd --permanent --add-port=3000-3100/tcp

# 查看已开放的端口
firewall-cmd --list-ports

# 永久删除端口
firewall-cmd --permanent --remove-port=8080/tcp

# 使永久配置生效
firewall-cmd --reload

3.4 Rich Rules(富规则)

当基础的端口和服务管理无法满足复杂的匹配条件时,就需要使用功能强大的富规则。

基本语法结构:

rule [family=”ipv4|ipv6”]
     [source address=”address[/mask]” [invert=”true”]]
     [destination address=”address[/mask]” [invert=”true”]]
     [service name=”service”]
     [port port=”port[-port]” protocol=”tcp|udp”]
     [log [prefix=”prefix”] [level=”level”] [limit value=”rate/duration”]]
     [accept|reject|drop|mark set=”mark[/mask]”]

实战示例:

# 只允许特定IP(192.168.1.100)访问SSH服务
firewall-cmd --permanent --add-rich-rule=’rule family=”ipv4” source address=”192.168.1.100” service name=”ssh” accept’

# 限制SSH连接速率(每分钟最多10次新连接)
firewall-cmd --permanent --add-rich-rule=’rule service name=”ssh” limit value=”10/m” accept’

# 拒绝特定IP(10.20.30.40)的所有访问,并记录警告级别日志
firewall-cmd --permanent --add-rich-rule=’rule family=”ipv4” source address=”10.20.30.40” log prefix=”Blocked-IP:” level=”warning” drop’

# 允许特定网段(10.0.0.0/8)访问MySQL端口(3306)
firewall-cmd --permanent --add-rich-rule=’rule family=”ipv4” source address=”10.0.0.0/8” port port=”3306” protocol=”tcp” accept’

# 端口转发:将外部对8080端口的访问转发到本机80端口
firewall-cmd --permanent --add-rich-rule=’rule family=”ipv4” forward-port port=”8080” protocol=”tcp” to-port=”80”’

# 应用所有永久配置
firewall-cmd --reload

# 查看所有富规则
firewall-cmd --list-rich-rules

3.5 Zone高级配置

为网络接口指定zone:

# 临时修改接口所属zone
firewall-cmd --zone=internal --change-interface=ens224

# 永久修改
firewall-cmd --permanent --zone=internal --change-interface=ens224
firewall-cmd --reload

基于源IP地址指定zone:
可以根据流量的来源IP应用不同的规则集,非常灵活。

# 将来自10.0.0.0/8的流量放入完全信任的trusted zone
firewall-cmd --permanent --zone=trusted --add-source=10.0.0.0/8

# 将来自192.168.1.0/24的流量放入work zone
firewall-cmd --permanent --zone=work --add-source=192.168.1.0/24

firewall-cmd --reload

创建自定义zone:

# 创建名为database的新zone
firewall-cmd --permanent --new-zone=database

# 配置该zone:允许MySQL服务、PostgreSQL端口,并限制来源网段
firewall-cmd --permanent --zone=database --add-service=mysql
firewall-cmd --permanent --zone=database --add-port=5432/tcp
firewall-cmd --permanent --zone=database --add-source=10.10.0.0/24

firewall-cmd --reload

# 查看新zone的配置
firewall-cmd --zone=database --list-all

3.6 NAT和IP伪装

开启IP伪装(MASQUERADE):

# 确保内核IP转发已开启
echo “net.ipv4.ip_forward = 1” >> /etc/sysctl.conf
sysctl -p

# 在指定zone(如public或external)上开启伪装
firewall-cmd --permanent --zone=public --add-masquerade
firewall-cmd --reload

配置端口转发:

# 将外部对8443端口的访问转发到内网服务器192.168.1.100的443端口
firewall-cmd --permanent --add-forward-port=port=8443:proto=tcp:toport=443:toaddr=192.168.1.100

# 将本机80端口的访问转发到本机8080端口(本地应用重定向)
firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8080

firewall-cmd --reload

3.7 Direct Rules(直接规则)

当firewalld的抽象层无法满足极端特定需求时,可以直接插入原生的iptables/nftables规则。

# 添加一条直接规则:允许TCP 9999端口
firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 9999 -j ACCEPT

# 查看所有直接规则
firewall-cmd --direct --get-all-rules

# 删除一条直接规则
firewall-cmd --permanent --direct --remove-rule ipv4 filter INPUT 0 -p tcp --dport 9999 -j ACCEPT

firewall-cmd --reload

注意: 直接规则会绕过firewalld的规则管理系统,直接插入到底层链中,可能与其他规则产生冲突,应谨慎使用。

第四章:实战对比案例

4.1 案例一:Web服务器防火墙配置

需求:

  • 开放HTTP(80)和HTTPS(443)端口。
  • SSH服务只允许特定的运维网段(10.20.0.0/16)访问。
  • 限制ICMP(ping)请求的速率。
  • 记录所有被拒绝的连接尝试。

iptables实现:

#!/bin/bash
# web-server-iptables.sh

# 清空规则
iptables -F
iptables -X

# 默认策略
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# 允许本地回环和已建立的连接
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# SSH - 只允许运维网段
iptables -A INPUT -p tcp --dport 22 -s 10.20.0.0/16 -j ACCEPT

# Web端口
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# ICMP限速
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT

# 记录被拒绝的包
iptables -A INPUT -j LOG --log-prefix “IPT-DROP: “ --log-level 4

# 保存
service iptables save

firewalld实现:

#!/bin/bash
# web-server-firewalld.sh

# 设置默认zone
firewall-cmd --set-default-zone=public

# 移除不需要的默认服务
firewall-cmd --permanent --remove-service=cockpit
firewall-cmd --permanent --remove-service=dhcpv6-client

# 添加Web服务
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https

# SSH只允许运维网段(使用富规则替代默认服务)
firewall-cmd --permanent --remove-service=ssh
firewall-cmd --permanent --add-rich-rule=’rule family=”ipv4” source address=”10.20.0.0/16” service name=”ssh” accept’

# ICMP限速
firewall-cmd --permanent --add-rich-rule=’rule protocol value=”icmp” limit value=”1/s” accept’

# 记录被拒绝的连接并设置zone默认动作为DROP
firewall-cmd --permanent --add-rich-rule=’rule log prefix=”FWD-DROP: ” level=”warning” limit value=”3/m”’
firewall-cmd --permanent --set-target=DROP

firewall-cmd --reload

对比分析:

方面 iptables firewalld
配置行数 约15行 约10行(命令)
可读性 需要理解链、表、规则顺序 语义更清晰(服务、源IP)
修改灵活性 通常需要重新执行整个脚本 支持单条规则的增删 (--add-*/--remove-*)
持久化 需显式执行 service iptables save 通过 --permanent 参数声明,--reload 生效

4.2 案例二:负载均衡器/网关配置

需求:

  • 作为内网(192.168.1.0/24)网关,提供NAT上网功能。
  • 将公网IP的80和443端口请求转发给内网的Web服务器(192.168.1.10)。
  • 允许运维网段(10.20.0.0/16)通过SSH访问网关。

iptables实现:

#!/bin/bash
# gateway-iptables.sh

# 开启IP转发
sysctl -w net.ipv4.ip_forward=1

# 清空规则,包括nat表
iptables -F
iptables -t nat -F
iptables -X

# 默认策略
iptables -P INPUT DROP
iptables -P FORWARD ACCEPT  # 网关需转发
iptables -P OUTPUT ACCEPT

# 基础规则:本地回环和已建立连接
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 允许内网访问网关本身
iptables -A INPUT -i ens224 -s 192.168.1.0/24 -j ACCEPT

# SSH访问控制
iptables -A INPUT -p tcp --dport 22 -s 10.20.0.0/16 -j ACCEPT

# NAT伪装 - 内网通过网关上网
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o ens192 -j MASQUERADE

# 端口转发 - Web服务 DNAT
iptables -t nat -A PREROUTING -i ens192 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.10:80
iptables -t nat -A PREROUTING -i ens192 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.10:443

# FORWARD链放行转发的Web流量
iptables -A FORWARD -d 192.168.1.10 -p tcp -m multiport --dports 80,443 -j ACCEPT
iptables -A FORWARD -s 192.168.1.10 -p tcp -m multiport --sports 80,443 -j ACCEPT

# 保存
service iptables save

firewalld实现:

#!/bin/bash
# gateway-firewalld.sh

# 开启IP转发
echo “net.ipv4.ip_forward = 1” >> /etc/sysctl.conf
sysctl -p

# 为不同接口分配不同zone:外网接口用external(默认开启伪装),内网接口用internal
firewall-cmd --permanent --zone=external --change-interface=ens192
firewall-cmd --permanent --zone=internal --change-interface=ens224

# 内网zone允许所有流量(高信任度)
firewall-cmd --permanent --zone=internal --set-target=ACCEPT

# 外网zone的SSH访问控制
firewall-cmd --permanent --zone=external --remove-service=ssh
firewall-cmd --permanent --zone=external --add-rich-rule=’rule family=”ipv4” source address=”10.20.0.0/16” service name=”ssh” accept’

# 配置端口转发
firewall-cmd --permanent --zone=external --add-forward-port=port=80:proto=tcp:toaddr=192.168.1.10
firewall-cmd --permanent --zone=external --add-forward-port=port=443:proto=tcp:toaddr=192.168.1.10

firewall-cmd --reload

4.3 案例三:数据库服务器安全加固

需求:

  • MySQL(3306)端口只允许三台指定的应用服务器(192.168.1.10-12)访问。
  • Redis(6379)端口只允许整个内网(192.168.1.0/24)访问。
  • SSH只允许来自跳板机(10.20.1.100)的访问。
  • 拒绝所有其他入站连接。

iptables实现:

#!/bin/bash
# database-iptables.sh

iptables -F
iptables -X

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# SSH只允许跳板机
iptables -A INPUT -p tcp --dport 22 -s 10.20.1.100 -j ACCEPT

# MySQL只允许三台应用服务器
iptables -A INPUT -p tcp --dport 3306 -s 192.168.1.10 -j ACCEPT
iptables -A INPUT -p tcp --dport 3306 -s 192.168.1.11 -j ACCEPT
iptables -A INPUT -p tcp --dport 3306 -s 192.168.1.12 -j ACCEPT

# Redis只允许内网
iptables -A INPUT -p tcp --dport 6379 -s 192.168.1.0/24 -j ACCEPT

# 监控端口(如node_exporter)
iptables -A INPUT -p tcp --dport 9100 -s 10.20.10.0/24 -j ACCEPT

service iptables save

firewalld实现:

#!/bin/bash
# database-firewalld.sh

# 创建并切换到专用的database zone
firewall-cmd --permanent --new-zone=database 2>/dev/null || true
firewall-cmd --set-default-zone=database

# SSH只允许跳板机
firewall-cmd --permanent --zone=database --add-rich-rule=’rule family=”ipv4” source address=”10.20.1.100” service name=”ssh” accept’

# MySQL允许三台应用服务器(使用循环)
for ip in 192.168.1.10 192.168.1.11 192.168.1.12; do
    firewall-cmd --permanent --zone=database --add-rich-rule=”rule family=\”ipv4\” source address=\”$ip\” port port=\”3306\” protocol=\”tcp\” accept”
done

# Redis允许内网
firewall-cmd --permanent --zone=database --add-rich-rule=’rule family=”ipv4” source address=”192.168.1.0/24” port port=”6379” protocol=”tcp” accept’

# 监控端口
firewall-cmd --permanent --zone=database --add-rich-rule=’rule family=”ipv4” source address=”10.20.10.0/24” port port=”9100” protocol=”tcp” accept’

# 设置该zone的默认策略为DROP
firewall-cmd --permanent --zone=database --set-target=DROP

firewall-cmd --reload

4.4 案例四:Kubernetes节点防火墙

Kubernetes环境对网络有特定要求,防火墙配置需与CNI插件协调。以下是基础配置示例。

需求:

  • 开放Kubernetes Master/Worker节点必需的通信端口。
  • 允许Pod网络(如Calico的10.244.0.0/16)和Service网络(10.96.0.0/12)的流量。
  • 允许节点间(192.168.1.0/24)的通信。
  • 开放NodePort服务范围(30000-32767)。

firewalld实现(推荐,但需测试):

#!/bin/bash
# k8s-node-firewalld.sh

# Master节点特定端口
if [ “$1” == “master” ]; then
    firewall-cmd --permanent --add-port=6443/tcp      # API Server
    firewall-cmd --permanent --add-port=2379-2380/tcp # etcd client/server
    firewall-cmd --permanent --add-port=10250/tcp     # Kubelet API
    firewall-cmd --permanent --add-port=10259/tcp     # kube-scheduler
    firewall-cmd --permanent --add-port=10257/tcp     # kube-controller-manager
fi

# 所有节点通用端口
firewall-cmd --permanent --add-port=10250/tcp     # Kubelet API
firewall-cmd --permanent --add-port=30000-32767/tcp # NodePort Services

# 允许Pod网络流量(以Calico VXLAN模式为例)
firewall-cmd --permanent --add-port=4789/udp      # VXLAN overlay 网络
firewall-cmd --permanent --add-port=5473/tcp      # Calico Typha(规模大时用)
firewall-cmd --permanent --add-port=179/tcp       # BGP(如果Calico用BGP)

# 允许Pod和Service CIDR的流量
firewall-cmd --permanent --add-rich-rule=’rule family=”ipv4” source address=”10.244.0.0/16” accept’  # Pod CIDR
firewall-cmd --permanent --add-rich-rule=’rule family=”ipv4” source address=”10.96.0.0/12” accept’   # Service CIDR

# 允许节点间通信
firewall-cmd --permanent --add-rich-rule=’rule family=”ipv4” source address=”192.168.1.0/24” accept’ # Node网络

# 开启伪装(大多数CNI插件需要)
firewall-cmd --permanent --add-masquerade

firewall-cmd --reload

# 注意:某些CNI插件(如Flannel的某些模式)可能与firewalld冲突。
# 复杂生产环境通常选择禁用firewalld,由CNI插件完全管理iptables/nftables规则。
# 如果必须开启,务必在测试环境充分验证。

第五章:迁移指南

5.1 从iptables迁移到firewalld

步骤一:导出现有iptables规则

iptables-save > /root/iptables-backup.rules

步骤二:分析规则并制定迁移计划
将iptables规则分类,映射到firewalld的概念:

  • 基础服务开放 → 使用 firewalld service
  • 端口开放 → 使用 firewalld port
  • IP访问控制 → 使用 firewalld rich rule
  • NAT/端口转发 → 使用 firewalld forward-portrich rule
  • 复杂或特殊规则 → 考虑使用 firewalld direct rule(最后手段)。

步骤三:创建并执行迁移脚本

#!/bin/bash
# migrate-to-firewalld.sh

# 停止并禁用iptables
systemctl stop iptables
systemctl disable iptables

# 启用并启动firewalld
systemctl unmask firewalld
systemctl enable firewalld
systemctl start firewalld

# 设置默认zone
firewall-cmd --set-default-zone=public

# 迁移基础服务(示例)
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https

# 迁移SSH访问控制(示例)
firewall-cmd --permanent --remove-service=ssh
firewall-cmd --permanent --add-rich-rule=’rule family=”ipv4” source address=”10.20.0.0/16” service name=”ssh” accept’

# 迁移自定义端口(示例)
firewall-cmd --permanent --add-port=8080/tcp

# 迁移NAT规则(示例)
firewall-cmd --permanent --add-masquerade

# 应用所有永久配置
firewall-cmd --reload

# 验证配置
firewall-cmd --list-all

步骤四:测试验证

# 检查关键服务的可访问性
curl -I http://localhost
ssh -o ConnectTimeout=5 user@server

# 检查规则是否生效
firewall-cmd --list-all
# 查看底层nftables规则(如果后端是nftables)
nft list ruleset

5.2 从firewalld回退到iptables

在某些兼容性场景下,可能需要回退。

#!/bin/bash
# rollback-to-iptables.sh

# 备份firewalld配置
cp -r /etc/firewalld /etc/firewalld.bak

# 停止并禁用firewalld
systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld

# 安装iptables服务(如未安装)
dnf install iptables-services -y

# 从备份恢复iptables规则
iptables-restore < /root/iptables-backup.rules

# 启用并启动iptables服务
systemctl enable iptables
systemctl start iptables

# 保存iptables规则
service iptables save

# 验证
iptables -L -n -v

5.3 并存方案(不推荐)

理论上可以配置两者共存,但极易导致规则冲突和管理混乱,仅适用于极端特殊且临时的场景。

# 编辑 /etc/firewalld/firewalld.conf
# 设置 IndirectInterface=no

强烈建议避免这种方案。

第六章:性能对比与测试

6.1 规则加载性能

测试环境:4核8G虚拟机。场景:加载1000条基于源IP的允许规则。

# 生成1000条iptables规则的脚本
for i in $(seq 1 1000); do
echo “iptables -A INPUT -s 10.10.$((i/256)).$((i%256)) -j ACCEPT”
done > /tmp/1000-rules.sh

# 测试iptables批量加载时间
time bash /tmp/1000-rules.sh
# 结果:约2.3秒

# 生成1000条firewalld富规则的脚本(效率低下的方式)
for i in $(seq 1 1000); do
echo “firewall-cmd --add-rich-rule=’rule family=\”ipv4\” source address=\”10.10.$((i/256)).$((i%256))\” accept’”
done > /tmp/1000-rules-fwd.sh

time bash /tmp/1000-rules-fwd.sh  # 每条都触发后台处理,极慢
# 结果:约180秒(不可接受)

# 正确方式:使用--permanent批量添加后一次reload
# 实际生产中应编写脚本生成包含所有规则的单个firewall-cmd命令或直接修改XML
# 模拟结果:约8秒(可接受)

结论: iptables在批量规则加载时速度优势明显。firewalld必须采用“批量永久添加+一次重载”的方式才能获得可接受的性能。

6.2 运行时性能

规则匹配的性能主要取决于内核的netfilter或nftables,前端工具影响较小。但底层机制有差异:

iptables的潜在瓶颈:

  • 规则通常是线性匹配,链表越长,匹配耗时可能线性增长。
  • 每次规则变更通常是全量替换。

nftables(firewalld默认后端)的优势:

  • 原生支持集合(set)映射(map),对于大量IP/端口的匹配,时间复杂度可接近O(1)。
  • 支持增量更新规则集。
  • 规则被编译成内核字节码,执行效率高。

实测对比概念:

# 假设有10000条独立源IP的允许规则
# iptables: 需要遍历链表,最坏情况比较10000次。
# nftables: 将IP放入一个set中,一次哈希查找即可。

# 使用hping3等工具测试大量规则下的包处理延迟
# nftables + set 的架构在规则数量庞大时优势显著。

6.3 内存占用

在包含1000条类似规则的情况下:

# 查看iptables相关内核内存占用(估算)
cat /proc/net/ip_tables_names
# 估算约 2MB

# 查看nftables规则内存占用
nft list ruleset | wc -l
# 估算约 1.2MB,且数据结构更优

结论: nftables在内存使用效率上通常优于传统的iptables,尤其是在规则集复杂时。

第七章:故障排查

7.1 常见问题:服务无法访问

排查步骤:

# 1. 确认服务进程是否在监听目标端口
ss -tlnp | grep :80

# 2. 确认防火墙服务状态
systemctl status firewalld   # 或 systemctl status iptables

# 3. 查看当前生效的防火墙规则
firewall-cmd --list-all --zone=$(firewall-cmd --get-default-zone)
# 或
iptables -L -n -v

# 4. 临时关闭防火墙进行测试(生产环境谨慎)
systemctl stop firewalld
# 如果此时服务可访问,则问题定位在防火墙规则

# 5. 查看防火墙日志
journalctl -u firewalld -f  --no-tail
# 或查看内核日志
dmesg | grep -i drop

常见原因:

  • 服务未添加到对应zone的允许列表中。
  • 网络接口绑定了错误的zone。
  • 富规则(rich rule)语法错误或逻辑矛盾。
  • 在iptables中,规则顺序导致提前被拒绝(规则从上到下匹配)。

7.2 常见问题:firewalld和Docker冲突

这是一个经典问题。Docker daemon默认会直接操作iptables/nftables来管理容器网络,可能与firewalld管理的规则冲突。

症状:

  • 容器内部无法访问外部网络。
  • 宿主机的端口映射 (-p 80:80) 不生效。
  • 重启firewalld服务后,Docker容器网络中断。

解决方案一:配置Docker不使用iptables(让firewalld全权管理)

# 编辑Docker daemon配置文件
cat > /etc/docker/daemon.json << ‘EOF’
{
  “iptables”: false
}
EOF
systemctl restart docker
# 然后需手动在firewalld中添加Docker网络所需的规则,较为复杂。

解决方案二:firewalld信任Docker网络(推荐)

# 将docker0网桥接口放入trusted zone(完全放行)
firewall-cmd --permanent --zone=trusted --add-interface=docker0

# 将Docker默认网段(通常是172.17.0.0/16)也加入trusted zone
firewall-cmd --permanent --zone=trusted --add-source=172.17.0.0/16

# 确保firewalld开启了IP伪装(容器访问外网需要)
firewall-cmd --permanent --add-masquerade

firewall-cmd --reload

解决方案三:使用firewalld预定义的docker zone(RHEL 9+/Rocky 9+)

firewall-cmd --permanent --zone=docker --add-interface=docker0
firewall-cmd --reload

7.3 常见问题:规则不生效

firewalld规则不生效:

# 1. 检查是否只使用了--permanent参数,但忘记或未成功执行--reload
firewall-cmd --reload

# 2. 检查流量对应的网络接口或源IP属于哪个zone
firewall-cmd --get-active-zones
firewall-cmd --get-zone-of-interface=eth0

# 3. 检查永久配置和运行时配置是否一致
firewall-cmd --list-all
firewall-cmd --list-all --permanent

# 4. 检查富规则优先级和冲突
firewall-cmd --list-rich-rules

iptables规则不生效:

# 1. 检查链的默认策略(policy),可能直接DROP而无需匹配规则
iptables -L -n | head -n 5

# 2. 检查规则顺序(规则从上到下匹配,第一条匹配的生效)
iptables -L -n --line-numbers

# 3. 查看规则计数器,看流量是否匹配到了预期规则
iptables -L -n -v  # 观察 ‘pkts’ 和 ‘bytes’ 列

7.4 常见问题:SSH锁定自己

修改防火墙规则时,错误地限制了SSH访问,导致自己无法连接。这是运维工作中的严重故障,必须预防。

预防措施:

# 方法1:使用at命令设置定时恢复(iptables)
echo “iptables-restore < /etc/sysconfig/iptables” | at now + 5 minutes
# 然后进行规则修改
# 如果修改成功且测试SSH正常,用 `atrm <job-id>` 取消定时任务。

# 方法2:使用firewall-cmd的--timeout参数(临时规则)
firewall-cmd --add-rich-rule=’rule family=”ipv4” source address=”0.0.0.0/0” service name=”ssh” drop’ --timeout=300
# 这条拒绝所有SSH的规则会在300秒后自动消失。

# 方法3:始终保持至少两个独立的SSH连接会话。
# 在一个会话中修改规则,用另一个会话来测试。

# 方法4:利用云服务器或物理服务器的控制台(VNC/IPMI/KVM)。

紧急恢复(如果已被锁定):

  1. 通过云服务商的控制台或物理服务器的IPMI/KVM直接登录系统。
  2. 执行 systemctl stop firewalldiptables -F 清空规则。
  3. 修复错误的防火墙规则。
  4. 重新启动防火墙服务。

7.5 调试工具

iptables调试:

# 在关键位置插入日志规则
iptables -I INPUT -j LOG --log-prefix “DEBUG-IN: “ --log-level 7
iptables -I OUTPUT -j LOG --log-prefix “DEBUG-OUT: “ --log-level 7
# 查看日志:tail -f /var/log/messages 或 journalctl -kf

# 使用TRACE目标(需加载模块)
modprobe nf_log_ipv4
iptables -t raw -A PREROUTING -p tcp --dport 80 -j TRACE
# 被追踪的包路径会在内核日志中详细打印。

firewalld调试:

# 开启对被拒绝连接的日志记录
firewall-cmd --set-log-denied=all
# 查看日志:journalctl -f | grep -E “REJECT|DROP”

# 增加firewalld自身日志级别
firewall-cmd --debug=10
# 详细日志会输出到journalctl -u firewalld

网络抓包(终极手段):

# 使用tcpdump查看数据包是否到达、被处理或被丢弃
tcpdump -i eth0 port 22 -nnvvv

第八章:最佳实践

8.1 选型决策树

需要选择防火墙工具?
    │
    ├── 新系统(RHEL 8+/Rocky 8+/AlmaLinux 8+)
    │       → 使用firewalld(官方默认,未来趋势)
    │
    ├── 旧系统维护(CentOS 7及更早)
    │       → 维持iptables现状(迁移风险可能大于收益)
    │
    ├── 需求简单(Web服务器、基础服务)
    │       → 使用firewalld(易用性好,管理方便)
    │
    ├── 需求复杂(高级路由、复杂NAT、状态跟踪)
    │       → 考虑直接使用iptables或原生nftables(灵活性高)
    │
    ├── Docker/K8s环境
    │       → firewalld + trusted/docker zone(需仔细测试)
    │       → 或禁用主机防火墙,使用K8s NetworkPolicy
    │
    ├── 自动化运维(Ansible/Puppet)
    │       → 优先firewalld(模块支持成熟)
    │
    └── 极致性能要求(超大量规则)
            → 原生nftables(避免firewalld抽象层开销)

8.2 安全加固清单

通用安全原则,无论使用哪种工具:

# 1. 默认拒绝所有入站连接
# iptables
iptables -P INPUT DROP
# firewalld
firewall-cmd --permanent --set-default-zone=drop
# 或在public zone设置
firewall-cmd --permanent --zone=public --set-target=DROP

# 2. 最小化开放端口
# 定期审计 `firewall-cmd --list-all` 或 `iptables -L`,移除不必要的规则。

# 3. SSH安全强化
# - 强制使用密钥认证,禁用密码。
# - 严格限制来源IP(使用富规则或iptables source匹配)。
# - 考虑修改默认端口(但非银弹,安全性提升有限)。

# 4. 限制ICMP
# 允许必要的echo-reply等,但限制echo-request(ping)的速率。

# 5. 防护基础网络攻击
# SYN洪水防护
iptables -A INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPT
# 或 firewalld 富规则 limit 参数。

# 6. 启用日志记录
# 记录被拒绝的连接,用于审计和攻击分析。

# 7. 定期审计规则
# 建立流程,定期检查防火墙规则,清理过期条目。

8.3 自动化管理

使用Ansible管理firewalld(推荐):

# firewall.yml
---
- name: Configure firewall
  hosts: webservers
  become: yes
  tasks:
  - name: Ensure firewalld is running
    service:
      name: firewalld
      state: started
      enabled: yes

  - name: Configure public zone services
    firewalld:
      zone: public
      service: “{{ item }}”
      permanent: yes
      state: enabled
    loop:
      - http
      - https
    notify: reload firewalld

  - name: Add SSH rich rule for admin network
    firewalld:
      zone: public
      rich_rule: ‘rule family=”ipv4” source address=”10.20.0.0/16” service name=”ssh” accept’
      permanent: yes
      state: enabled
    notify: reload firewalld

  - name: Remove default SSH rule (if using rich rule above)
    firewalld:
      zone: public
      service: ssh
      permanent: yes
      state: disabled
    notify: reload firewalld

  handlers:
  - name: reload firewalld
    command: firewall-cmd --reload

8.4 备份与恢复

firewalld备份:

# 备份整个配置目录
tar -czvf firewalld-backup-$(date +%Y%m%d).tar.gz /etc/firewalld/

# 恢复
systemctl stop firewalld
tar -xzvf firewalld-backup-20250107.tar.gz -C /
systemctl start firewalld
firewall-cmd --reload

iptables备份:

# 备份规则
iptables-save > iptables-backup-$(date +%Y%m%d).rules
ip6tables-save > ip6tables-backup-$(date +%Y%m%d).rules

# 恢复
iptables-restore < iptables-backup-20250107.rules
service iptables save  # 保存到持久化文件

自动化备份脚本示例:

#!/bin/bash
# /etc/cron.daily/firewall-backup
BACKUP_DIR=”/backup/firewall”
DATE=$(date +%Y%m%d)
mkdir -p $BACKUP_DIR

# 备份firewalld配置
if systemctl is-active --quiet firewalld; then
    tar -czf $BACKUP_DIR/firewalld-$DATE.tar.gz /etc/firewalld/ 2>/dev/null
fi

# 备份当前内核中的iptables规则(无论前端用什么)
iptables-save > $BACKUP_DIR/iptables-runtime-$DATE.rules 2>/dev/null

# 清理30天前的旧备份
find $BACKUP_DIR -type f -mtime +30 -delete

第九章:高级话题与总结

9.1 nftables原生使用

如果你追求极致性能和控制,可以直接使用nftables,它正在逐步取代iptables。

# 查看当前nftables规则集
nft list ruleset

# 创建并应用一个简单的nftables配置
cat > /etc/nftables.conf << ‘EOF’
#!/usr/sbin/nft -f
flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;

        # 允许已建立/相关的连接
        ct state established,related accept

        # 允许回环接口
        iifname “lo” accept

        # 允许SSH(来自特定网段)
        tcp dport 22 ip saddr 10.20.0.0/16 accept

        # 允许HTTP/HTTPS
        tcp dport { 80, 443 } accept

        # 限速ICMP
        ip protocol icmp limit rate 1/second accept
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}
EOF
nft -f /etc/nftables.conf
systemctl enable nftables

9.2 选型建议总结

场景 推荐方案 核心理由
RHEL/CentOS/Rocky/AlmaLinux 新系统(8+) firewalld 发行版官方默认,与系统集成好,支持动态更新和zone概念。
老旧系统维护(CentOS 7等) 维持现有iptables 迁移可能引入风险,稳定优先。
简单应用服务器(Web、App) firewalld 配置直观,易于管理和自动化。
复杂网关/NAT路由器 iptables 或 原生nftables 对规则和网络流有更精细的控制。
Docker/K8s 环境 firewalld (配合trusted zone) 或 禁用 需平衡安全与兼容性,复杂集群常禁用主机防火墙。
高性能需求(海量规则) 原生nftables 绕过firewalld抽象层,性能最优,数据结构高效。
自动化运维(Ansible) firewalld Ansible模块对firewalld支持完善、稳定。

9.3 核心观点

  1. 理解层级关系:firewalld是iptables/nftables的配置管理层,而非替代品。理解底层的netfilter/nftables原理,对于解决复杂问题和深度排查故障至关重要。
  2. 拥抱趋势,但不盲从:在新系统上,firewalld是更现代、更易管理的选择。但对于运行多年、规则稳定的老系统,“不坏不修” 往往是更明智的策略。
  3. 安全原则是根本:无论选择哪个工具,“默认拒绝”“最小权限”“定期审计” 这些安全原则永远不会过时。
  4. 自动化是必由之路:手动管理防火墙规则无法适应现代基础设施的规模和变化速度。必须使用Ansible、Terraform等工具实现配置的代码化、版本化和自动化。
  5. 防火墙是整体安全的一部分:它只是防御纵深中的一层。需要与系统 hardening、入侵检测系统(IDS)、Web应用防火墙(WAF)以及持续的安全监控相结合,才能构建 robust 的安全体系。

最终,最好的防火墙配置,是你和你的团队能够清晰理解、方便维护并能快速排查故障的配置。过于复杂而无人能懂的规则,其本身就是安全隐患。

希望这份详细的对比与实践指南,能帮助你在Linux防火墙的选型与使用上做出更明智的决策。技术社区的生命力在于分享与交流,欢迎在云栈社区继续探讨相关问题。


本文基于 Rocky Linux 9.3、firewalld 1.3.4、iptables 1.8.10 环境编写,所述原理与主要操作同样适用于其他主流Linux发行版。




上一篇:基于大语言模型的实时股票预测框架PriceSeer研究
下一篇:RPC vs HTTP:微服务架构下远程调用技术选型深度解析
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-16 21:29 , Processed in 0.241585 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表