firewalld 防火墙全面详解:从核心概念到高级实战
firewalld 是 RHEL、CentOS、Fedora 等发行版的默认防火墙管理工具,采用“区域(Zone)”模型替代传统的规则链堆叠,支持运行时与永久配置分离、富规则、策略对象等高级能力。它的核心价值在于:用“信任级别”抽象组织安全策略,让多网卡、多场景的防火墙管理更清晰、更不易出错。本文从核心概念、基础操作、高级功能到实战场景,系统梳理 firewalld 的完整用法。
一、firewalld 是什么
firewalld 是一个动态防火墙管理器,提供支持网络/防火墙区域的防火墙,用于定义网络连接或接口的信任级别。它支持 IPv4、IPv6、以太网桥和 IP sets,并且将运行时配置与永久配置分离。
与 iptables 最本质的区别在于:firewalld 引入了“区域(Zone)”这一层抽象。你不再直接面对裸的规则链,而是先把网卡或来源地址归属到某个信任级别的区域,区域内置的规则集合自动作用于该区域上的所有流量。
二、核心概念
2.1 区域(Zone)
区域是对网络“信任级别”的抽象。firewalld 自带多个预定义区域,从最保守到最开放依次为:
| 区域 | 信任级别 | 典型用途 |
|---|---|---|
drop | 最低(最安全) | 静默丢弃所有入站流量,不返回任何响应 |
block | 极低 | 拒绝入站,但返回 ICMP 不可达响应 |
public | 默认 | 公共网络,仅放行明确指定的服务 |
external | 较低 | 路由器外部网络,启用地址伪装 |
dmz | 中等 | DMZ 区域服务器 |
work | 较高 | 工作网络,信任同网段主机 |
home | 高 | 家庭网络 |
internal | 高 | 内部网络 |
trusted | 最高(最宽松) | 允许所有流量 |
Ubuntu 上 firewalld 的默认区域通常也是 public。未显式绑定到其他区域的网络接口,自动归入默认区域。
关键原则:区域越开放,越应该只用在可信网络接口上。一台机器同时有公网网卡和内网网卡时,应分别划到 public 和 trusted 两个区域。
2.2 运行时 vs 永久配置
firewalld 将配置分为两层:
- 运行时配置:立即生效,但重启服务或系统后丢失。适合测试和临时调整。
- 永久配置:写入磁盘,重启后依然存在。使用
--permanent标志添加。
优先级上,运行时配置高于永久配置。执行 firewall-cmd --reload 后,永久配置会覆盖运行时中未保存为永久的修改。
实用技巧:如果在运行时测试了一条规则且运行正常,可以将其保存为永久配置:
sudo firewall-cmd --runtime-to-permanent
2.3 策略对象(Policy,firewalld 0.9+)
较新版本的 firewalld 引入了策略对象,用于描述区域之间、区域与出站流量之间的策略,比传统的 zone 更灵活。
策略对象允许你将 firewalld 的原语(如服务、端口和富规则)附加到策略,并以有状态和单向的方式应用到区域间传输的流量上。
符号区域 HOST 和 ANY 可用于 ingress/egress:
HOST:来自运行 firewalld 主机的流量,或到该主机的流量。ANY:所有当前和将来的区域,充当通配符。
三、基础操作命令
3.1 启停与状态查看
# 启动并设为开机自启
sudo systemctl enable --now firewalld
# 查看运行状态
sudo systemctl status firewalld
sudo firewall-cmd --state
# 停止并禁用
sudo systemctl stop firewalld
sudo systemctl disable firewalld
3.2 区域管理
# 查看默认区域
sudo firewall-cmd --get-default-zone
# 设置默认区域(该更改总是永久的)
sudo firewall-cmd --set-default-zone=work
# 查看所有活跃区域及绑定的接口
sudo firewall-cmd --get-active-zones
# 查看指定区域的完整配置
sudo firewall-cmd --zone=public --list-all
# 列出所有区域的配置
sudo firewall-cmd --list-all-zones
# 将接口绑定到指定区域
sudo firewall-cmd --zone=trusted --change-interface=eth1
sudo firewall-cmd --reload
3.3 放行服务与端口
# 永久放行 HTTP 和 HTTPS(按服务名)
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload
# 查看预定义服务列表
sudo firewall-cmd --get-services
# 放行自定义端口(必须带协议类型)
sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp
sudo firewall-cmd --permanent --zone=public --add-port=51820/udp
# 放行端口范围
sudo firewall-cmd --permanent --zone=public --add-port=8080-8090/tcp
sudo firewall-cmd --reload
# 查看已放行的端口
sudo firewall-cmd --zone=public --list-ports
高频陷阱:--permanent 是必须的。不带 --permanent 的规则只在当前会话开放,机器重启或 firewalld 重启后就会丢失,这正是很多“端口明明加了却连不上”现象的根源。
3.4 移除规则
sudo firewall-cmd --permanent --zone=public --remove-service=http
sudo firewall-cmd --permanent --zone=public --remove-port=8080/tcp
sudo firewall-cmd --reload
3.5 重新加载
每次修改 --permanent 规则后,都必须执行 reload 才能生效:
sudo firewall-cmd --reload
reload 不会中断现有连接;--complete-reload 会完全重置(断开连接)。
四、高级功能
4.1 富规则(Rich Rules)
富规则是 firewalld 最强大的功能,用于表达服务/端口不足以描述的复杂防火墙规则。
基本语法:
rule [family="ipv4|ipv6"] [priority="priority"] [conditions] [actions]
限制来源访问特定端口:
sudo firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="10.0.0.0/8"
port protocol="tcp" port="22" accept'
限制连接频率(防暴力破解):
sudo firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
service name="ssh"
limit value="3/m"
accept'
记录并拒绝特定来源:
sudo firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="192.168.1.100"
reject'
富规则的优先级:priority 参数范围是 -32768 到 32767,数值越低优先级越高。低于 0 的规则被重定向到带 _pre 后缀的链中,高于 0 的进入 _post 链,等于 0 的按操作进入 _log、_deny 或 _allow 链。
4.2 端口转发与 NAT
DNAT(目标地址转换)——将公网流量转发到内部服务器:
# 将公网 IP 192.0.2.1 的 443 端口转发到内网 192.51.100.20 的 443
sudo firewall-cmd --permanent --add-rich-rule='
rule family="ipv4"
destination address="192.0.2.1"
forward-port port="443" protocol="tcp" to-port="443" to-addr="192.51.100.20"'
sudo firewall-cmd --reload
启用 IP 伪装(SNAT 的必要条件):
sudo firewall-cmd --permanent --zone=public --add-masquerade
sudo firewall-cmd --reload
# 验证
sudo firewall-cmd --query-masquerade
端口转发依赖源地址转换,必须开启 masquerade,否则内网服务器响应包无法正确回传,造成单向通信失败。
4.3 策略对象(Policy)实战
使用策略对象过滤区域间流量,例如限制 Podman 容器到其他区域的访问:
# 创建新策略
sudo firewall-cmd --permanent --new-policy podmanToAny
# 默认拒绝,只放行必要服务
sudo firewall-cmd --permanent --policy podmanToAny --set-target REJECT
sudo firewall-cmd --permanent --policy podmanToAny --add-service dhcp
sudo firewall-cmd --permanent --policy podmanToAny --add-service dns
sudo firewall-cmd --permanent --policy podmanToAny --add-service https
# 定义 ingress 和 egress 区域
sudo firewall-cmd --permanent --policy podmanToAny --add-ingress-zone podman
sudo firewall-cmd --permanent --policy podmanToAny --add-egress-zone ANY
sudo firewall-cmd --reload
# 验证
sudo firewall-cmd --info-policy podmanToAny
策略的 target 可选值:ACCEPT、DROP、REJECT、CONTINUE(默认)。
4.4 IP sets(大量 IP 集合管理)
当需要封禁/放行成百上千个 IP 时,逐条富规则效率极低。firewalld 支持 ipset:
# 创建 IP 集合
sudo firewall-cmd --permanent --new-ipset=blocklist --type=hash:ip
# 添加条目
sudo firewall-cmd --permanent --ipset=blocklist --add-entry=1.2.3.4
sudo firewall-cmd --permanent --ipset=blocklist --add-entry=5.6.7.8
# 在富规则中引用
sudo firewall-cmd --permanent --zone=public --add-rich-rule='
rule source ipset="blocklist" drop'
sudo firewall-cmd --reload
五、与 Docker 的冲突处理
这是 Ubuntu 用户从 UFW 迁移到 firewalld 时最容易踩坑的地方。Docker 默认会自行写入 iptables 规则,可能绕过 firewalld 的区域规则。即使你没有在 firewalld 中放行某个端口,Docker 映射的端口仍然可能对外可达。
排查步骤:
# 检查 firewalld 状态
sudo systemctl status firewalld
sudo firewall-cmd --list-all
# 检查底层 iptables 规则
sudo iptables -L -n -v
处理方案:
- 调整启停顺序:
systemctl restart firewalld→systemctl restart docker,让 Docker 重建规则链。 - 使用 host 网络模式:容器直接使用宿主网络,避免 bridge 与 iptables 交互。
- 修改 Docker 配置:在
/etc/docker/daemon.json中设置"iptables": false(需自行管理网络规则)。 - 为 Docker 创建专用 zone:绑定
docker0接口,按需放行。
六、配置持久化与文件管理
firewalld 的所有永久配置存储在 /etc/firewalld/ 下:
zones/— 区域配置(如public.xml)services/— 自定义服务定义ipsets/— IP 集合policies/— 策略对象direct.xml— direct 规则firewalld.conf— 全局配置
在自动化运维(Ansible、SaltStack)中,直接管理这些 XML 文件往往比执行命令更可靠。
七、安全操作要点
- 不要同时运行多个防火墙管理工具。UFW、firewalld、iptables 同时运行会竞争对内核 Netfilter 的写权限,导致规则互相覆盖、端口状态不可预期。
- 远程操作前确保 SSH 可达。变更防火墙前,先确认新规则会放行 SSH,否则一旦网络断开将无法连接。
- 变更前备份规则:
sudo firewall-cmd --runtime-to-permanent sudo cp /etc/firewalld/zones/public.xml ~/backup-public.xml - 日志排查:
sudo journalctl -u firewalld -f
八、总结
firewalld 的学习曲线比 UFW 陡,但它的核心价值在于区域模型提供的策略组织能力。理解以下三点,就能掌握 firewalld 的精髓:
- 区域是信任级别的抽象:把网卡/来源归入合适的区域,比逐条写规则更清晰。
--permanent+--reload是标准流程:养成习惯,避免规则丢失。- 富规则和策略对象是进阶关键:它们决定了你能否处理限速、区域间过滤、容器网络等复杂场景。
对于运行在 Ubuntu 上的服务,如果只做简单的端口放行,UFW 可能更直接。但如果你管理混合 Linux 环境、需要多网卡隔离、或者追求更精细的流量控制,firewalld 是更值得投入学习的选择。