firewalld作为Linux系统上的动态防火墙管理工具,其设计哲学与传统的iptables有着本质区别。我初次接触firewalld时,最让我惊讶的是它引入了"区域(Zone)"这一抽象概念——这就像给不同安全级别的网络环境划分了明确的边界,每个边界都有预设的安全策略。
想象一下,你家的前门、后门和车库门可能需要不同级别的安全措施。firewalld的区域设计正是基于这样的现实需求:
trusted区域:相当于你家的客厅,所有来访者都被视为可信的。我通常只在完全可控的内网环境使用这个设置,比如开发测试集群内部通信。
home/internal区域:类似你家的卧室,允许一些基本活动但有所限制。这个区域默认放行SSH、mdns等常见服务,适合办公网络环境。
public区域:就像你家的大门,默认配置最为严格。这也是firewalld的默认区域,新安装的系统都会使用这个区域,仅放行dhcpv6-client和ssh服务。
dmz区域:相当于你家的门廊,只允许特定的交互。我常把这个区域用于面向公众的服务,比如Web服务器。
block/drop区域:这两个区域都拒绝入站连接,但行为不同。block会返回拒绝响应,而drop则直接丢弃数据包不作回应。后者更安全但也更难排查问题。
实际经验:生产环境中,我强烈建议从最严格的public区域开始,然后根据需要逐步开放权限。我曾见过太多因为初始区域设置过于宽松而导致的安全事件。
firewalld的另一个精妙设计是将具体的端口/协议组合抽象为"服务"。这带来了几个实际好处:
--add-service=http比记住要开放80/tcp直观得多查看系统预定义的服务列表:
bash复制ls /usr/lib/firewalld/services/*.xml
每个服务都是一个简单的XML文件,定义了协议、端口等信息。例如http服务:
xml复制<?xml version="1.0" encoding="utf-8"?>
<service>
<short>WWW (HTTP)</short>
<description>HTTP is the protocol used to serve Web pages.</description>
<port protocol="tcp" port="80"/>
</service>
firewalld采用双配置模式,这是很多新手容易混淆的地方:
| 配置类型 | 生效方式 | 持久性 | 适用场景 |
|---|---|---|---|
| 运行时(Runtime) | 立即生效 | 重启后丢失 | 临时测试、紧急调整 |
| 永久(Permanent) | 需--reload | 永久保存 | 生产环境标准配置 |
我常用的工作流程是:
血泪教训:永远记得在关键操作前检查是否加了--permanent参数。我曾因为忘记加这个参数,导致服务器重启后所有防火墙规则丢失,引发严重故障。
在深入防火墙规则前,我们需要确保firewalld服务本身正常运行:
bash复制# 检查服务状态(两种方式)
systemctl status firewalld
firewall-cmd --state
# 启停控制
systemctl start firewalld # 启动
systemctl stop firewalld # 停止(危险!会清空所有运行时规则)
systemctl restart firewalld # 重启(会保留运行时配置)
# 开机自启设置
systemctl enable firewalld # 启用自启
systemctl disable firewalld # 禁用自启
重要细节:
stop命令会立即停用防火墙,所有流量都将不受限制(相当于临时禁用防护)restart会保留当前的运行时配置,但会中断现有连接--reload而非restart,它能在不中断现有连接的情况下重载配置bash复制# 查看当前默认区域
firewall-cmd --get-default-zone
# 修改默认区域(永久生效)
firewall-cmd --set-default-zone=internal --permanent
# 查看所有可用区域
firewall-cmd --get-zones
# 查看活跃区域(已绑定接口或源地址的区域)
firewall-cmd --get-active-zones
--list-all参数可以展示区域完整配置:
bash复制firewall-cmd --zone=public --list-all
典型输出示例:
code复制public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: ssh dhcpv6-client
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
字段解析:
target: 默认策略(default/ACCEPT/DROP/REJECT)interfaces: 绑定的物理接口sources: 绑定的源IP/网段services: 允许的服务ports: 直接允许的端口masquerade: 是否启用IP伪装(NAT)将网络接口分配到特定区域:
bash复制# 查看接口当前所属区域
firewall-cmd --get-zone-of-interface=eth0
# 修改接口区域绑定(永久)
firewall-cmd --zone=work --change-interface=eth0 --permanent
经验之谈:
bash复制# 临时开放端口(重启失效)
firewall-cmd --add-port=8080/tcp
# 永久开放端口
firewall-cmd --add-port=8080/tcp --permanent
# 开放端口范围
firewall-cmd --add-port=8000-8080/tcp --permanent
# 关闭端口
firewall-cmd --remove-port=8080/tcp --permanent
# 查询端口状态
firewall-cmd --query-port=8080/tcp
注意事项:
查看所有预定义服务:
bash复制firewall-cmd --get-services
自定义服务创建步骤:
bash复制cp /usr/lib/firewalld/services/http.xml /etc/firewalld/services/myapp.xml
bash复制firewall-cmd --reload
实用技巧:
bash复制# 启用IP伪装(相当于SNAT)
firewall-cmd --zone=public --add-masquerade --permanent
# 禁用IP伪装
firewall-cmd --zone=public --remove-masquerade --permanent
应用场景:
将外部请求转发到内部服务器:
bash复制# 基本转发:本地80 → 内网192.168.1.100:8080
firewall-cmd --add-forward-port=port=80:proto=tcp:toaddr=192.168.1.100:toport=8080 --permanent
# 带源IP限制的转发
firewall-cmd --add-rich-rule='rule family="ipv4" source address="203.0.113.0/24" forward-port port="80" protocol="tcp" to-port="8080" to-addr="192.168.1.100"' --permanent
排错要点:
bash复制sysctl net.ipv4.ip_forward=1
富规则提供了更精细的控制能力:
bash复制# 允许特定IP访问特定端口
firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.168.1.100" port port="22" protocol="tcp" accept' --permanent
# 拒绝特定IP访问
firewall-cmd --add-rich-rule='rule family="ipv4" source address="10.0.0.5" reject' --permanent
# 时间限制规则(仅工作日9-18点允许访问)
firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="http" accept' --permanent --time="9:00-18:00" --weekdays="Mon,Tue,Wed,Thu,Fri"
优势分析:
| 特性 | firewalld | iptables |
|---|---|---|
| 配置管理 | 动态更新,无需重启 | 静态规则,需完全重载 |
| 规则组织 | 基于区域和服务的抽象 | 基于链和表的直接规则 |
| 前端界面 | firewall-cmd和GUI工具 | 直接使用iptables命令 |
| 后端实现 | 仍然使用nftables/iptables | 直接操作内核netfilter |
| 配置存储 | XML文件 | 直接写入内核或规则文件 |
虽然firewalld增加了一层抽象,但在现代硬件上性能差异可以忽略不计。我的实测数据显示:
适用场景建议:
bash复制iptables -S
iptables -t nat -S
bash复制systemctl stop firewalld
systemctl disable firewalld
yum install iptables-services -y
systemctl enable iptables
重要提醒:不要同时启用firewalld和iptables服务,这会导致规则冲突和不可预测的行为。
典型LAMP服务器配置流程:
bash复制# 设置默认区域
firewall-cmd --set-default-zone=public --permanent
# 放行Web服务
firewall-cmd --add-service=http --permanent
firewall-cmd --add-service=https --permanent
# 限制SSH访问
firewall-cmd --remove-service=ssh --permanent
firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="ssh" accept' --permanent
# 放行Ping(ICMP)
firewall-cmd --add-icmp-block-inversion --permanent
# 应用配置
firewall-cmd --reload
安全增强建议:
firewall-cmd --list-all-zonesMySQL数据库安全配置:
bash复制# 创建专用区域
firewall-cmd --new-zone=mysql --permanent
# 设置默认策略为拒绝
firewall-cmd --zone=mysql --set-target=DROP --permanent
# 仅允许应用服务器访问
firewall-cmd --zone=mysql --add-source=192.168.1.50/32 --permanent
firewall-cmd --zone=mysql --add-port=3306/tcp --permanent
# 将配置应用到网卡
firewall-cmd --zone=mysql --change-interface=eth1 --permanent
# 应用配置
firewall-cmd --reload
使用firewalld实现租户网络隔离:
bash复制# 为每个租户创建专用区域
for tenant in tenant1 tenant2 tenant3; do
firewall-cmd --new-zone=$tenant --permanent
firewall-cmd --zone=$tenant --add-service=ssh --permanent
done
# 将不同租户的VLAN接口分配到不同区域
firewall-cmd --zone=tenant1 --change-interface=eth0.100 --permanent
firewall-cmd --zone=tenant2 --change-interface=eth0.200 --permanent
# 设置默认互通规则
firewall-cmd --add-rich-rule='rule family="ipv4" source zone="tenant1" destination zone="tenant2" drop' --permanent
firewall-cmd --add-rich-rule='rule family="ipv4" source zone="tenant2" destination zone="tenant1" drop' --permanent
# 应用配置
firewall-cmd --reload
firewall-cmd --list-alltelnet <IP> <PORT>journalctl -u firewalldcp -a /etc/firewalld/ ~/firewalld_backupbash复制# 查看当前连接
ss -tulnp
# 监控拒绝的连接
journalctl -u firewalld -f | grep DENIED
bash复制#!/bin/bash
DATE=$(date +%Y%m%d)
BACKUP_DIR="/backup/firewalld/$DATE"
mkdir -p $BACKUP_DIR
firewall-cmd --list-all-zones > $BACKUP_DIR/zones_$DATE.conf
cp -a /etc/firewalld/ $BACKUP_DIR/
bash复制# 使用ipset示例
firewall-cmd --new-ipset=trusted_ips --type=hash:ip --permanent
firewall-cmd --ipset=trusted_ips --add-entry=192.168.1.100 --permanent
firewall-cmd --add-rich-rule='rule source ipset="trusted_ips" service name="ssh" accept' --permanent
经过多年实践,我发现firewalld的最佳使用方式是:充分利用其高级特性(如富规则、ipset等),同时保持配置的简洁性和可读性。每次修改前做好备份,复杂变更先在测试环境验证,这些习惯帮我避免了很多潜在问题。