Firewalld 不允许多区域同时绑定同一接口,因每个接口只能属一个活跃zone;需通过source绑定实现逻辑隔离,并开启IP转发与正确配置rich rule、masquerade等才能生效。
Firewalld 的多区域策略不是“同时生效多个区域”,而是靠接口绑定 + 源地址匹配实现逻辑隔离;直接给同一接口分配多个区域会报错,必须用 rich rule 或 zone targeting 配合 source-based 规则。
为什么不能直接把一个网卡同时加到 public 和 internal 区域
Firewalld 要求每个网络接口(
、
等)只能属于一个活跃 zone。执行
后,
会自动从原 zone(如
)移出。强行重复添加会返回错误:
。
真正需要的是:同一物理接口接入不同子网(如
和
),让它们走不同策略 —— 这得靠
绑定而非接口绑定。
用
把源网段绑定到
区域
用
把另一网段绑定到
区域
确保这些
规则优先级高于接口默认 zone(Firewalld 按 “source → interface → default” 顺序匹配)
如何用 rich rule 实现跨区域的精细控制(比如只允许 internal 用户访问数据库端口)
当 zone 级别策略不够细(例如
zone 默认放行所有服务,但你只想开放
给特定 IP),就得在目标 zone 里加
。它比 zone-level 设置更优先,且支持源地址、端口、协议、日志等组合条件。
CentOS Linux 7.9.2009
CentOS Linux 7.9.2009是传统CentOS Linux 7的最后主要版本,也是很多企业历史服务器中仍可能遇到的系统版本。它以稳定、兼容RHEL 7生态、文档丰富和软件支持广泛著称,曾长期用于Web服务、数据库、虚拟化节点和企业内部业务系统。不过CentOS Linux 7已于2024年6月30日停止维护,现在继续使用会面临安全补丁缺失风险。该版本更适合旧业务迁移、历史环境恢复或离线兼容性测试。
下载
示例:只允许来自
的 TCP 请求访问本机
,并记录匹配日志:
注意
表示这条规则生效于
zone 的上下文中,不是全局规则
如果该 IP 实际走的是
zone(比如没配
绑定),这条规则不会触发 —— rich rule 不跨 zone 生效
日志前缀
会出现在
或
中,方便排查
多区域策略下最容易被忽略的路由与转发问题
Firewalld 默认关闭 IP 转发(
),而跨子网流量隔离往往依赖主机做路由或 NAT。如果你绑定了两个
到不同 zone,但没打开转发,包会在内核层被丢弃,firewalld 根本收不到 —— 此时
看起来一切正常,但实际不通。
先确认转发开启:
应返回
;否则运行
若涉及 SNAT/DNAT(如让 internal 用户通过本机访问外网),需在对应 zone 启用伪装:
检查
是否出现 masquerade 规则,避免只配 firewalld 却忘了底层 netfilter 生效条件
多区域本质是 source + interface + default 的三级匹配链,不是并行策略容器;真正复杂的地方在于,一旦引入 rich rule、masquerade、forward-port,就必须同步检查内核参数、路由表、以及
输出中是否真有 source 条目 —— 很多人卡在“规则写了却没生效”,其实是 source 绑定失败或转发未开。
eth0ens33firewall-cmd --zone=internal --add-interface=eth0eth0publicERROR: ZONE_ALREADY_SET: 'eth0' already bound to a zone192.168.10.0/24192.168.20.0/24sourcefirewall-cmd --permanent --zone=internal --add-source=192.168.10.0/24internalfirewall-cmd --permanent --zone=public --add-source=192.168.20.0/24publicsourceinternal3306rich rule192.168.10.1003306firewall-cmd --permanent --zone=internal --add-rich-rule='rule family="ipv4" source address="192.168.10.100" port port="3306" protocol="tcp" accept log prefix="mysql-access" level="info'--zone=internalinternalpublicsourceprefix="mysql-access"/var/log/messagesjournalctl -u firewalldnet.ipv4.ip_forward=0sourcefirewall-cmd --list-all-zonessysctl net.ipv4.ip_forward1echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf && sysctl -pfirewall-cmd --permanent --zone=internal --add-masqueradeiptables -t nat -L POSTROUTINGfirewall-cmd --get-active-zones