在CentOS系统中,使用firewalld的富规则(Rich Rules)来实现复杂的IP黑白名单,本质上就是利用firewalld提供的高级规则语法,针对特定IP地址、网段或服务端口进行精细化的访问控制。简单来说,你需要创建一条富规则,指定源IP地址、动作(accept或drop)、以及可选的端口和协议,然后将其分配到对应的zone中。这种方式比单纯使用iptables命令更直观、更易于管理,也更符合CentOS 7/8/9的默认防火墙架构。下面我会从原理、配置步骤、高级用法到排错维护,把这套方案完整讲透。

一、为什么要用firewalld富规则而不是iptables直接写规则

很多老运维习惯直接操作iptables,但在CentOS 7以后,firewalld才是默认的防火墙管理工具。直接写iptables规则有几个问题:第一,重启后容易丢失,除非手动保存;第二,规则之间的优先级关系不清晰,后期维护成本高;第三,和systemd的zone管理体系脱节。而firewalld的富规则是zone体系下的原生能力,规则持久化自动完成,且支持运行时动态修改,不需要重启防火墙服务。对于需要频繁调整IP黑白名单的场景,富规则是最合适的选择。

二、firewalld富规则的核心语法结构

富规则的基本格式如下:

firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.1.100" accept'

这条命令的含义是:在public zone中,永久添加一条规则,允许来自192.168.1.100这个IPv4地址的所有流量通过。反过来,如果要拉黑某个IP,把accept改成drop就行:

firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="10.0.0.55" drop'

注意,富规则支持的参数远不止这些。你可以指定端口、协议、日志记录、动作等多个维度,这就是它被称为"富"规则的原因。

三、实现IP白名单的完整操作流程

假设你的服务器运行的是Web服务,只允许特定几个IP访问80和443端口,其他全部拒绝。操作步骤如下:

第一步,先清空zone中可能存在的旧规则,避免冲突:

firewall-cmd --zone=public --list-rich-rules

第二步,添加白名单IP的富规则,限定端口:

firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="203.0.113.10" port protocol="tcp" port="80" accept'

firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="203.0.113.10" port protocol="tcp" port="443" accept'

firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="198.51.100.20" port protocol="tcp" port="80" accept'

firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="198.51.100.20" port protocol="tcp" port="443" accept'

第三步,设置默认拒绝策略,确保不在白名单内的IP无法访问:

firewall-cmd --permanent --zone=public --set-target=DROP

第四步,重新加载防火墙使规则生效:

firewall-cmd --reload

这样配置后,只有203.0.113.10和198.51.100.20这两个IP能访问80和443端口,其他所有来源的流量都会被直接丢弃。

四、实现IP黑名单的进阶配置

黑名单场景更常见,比如你发现某个IP在持续扫描你的SSH端口,需要立即封禁。富规则同样支持:

firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.0.2.100" port protocol="tcp" port="22" drop'

如果你想封禁整个网段,比如192.0.2.0/24这个C段:

firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.0.2.0/24" drop'

更高级的做法是,封禁某个IP但同时记录日志,方便后续审计:

firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.0.2.100" log prefix="BLOCKED_IP" level="warning" drop'

这条规则会在系统日志中留下"BLOCKED_IP"前缀的警告信息,你可以通过journalctl或/var/log/messages查看被拦截的记录。

五、黑白名单混合使用的策略设计

在实际生产环境中,单纯的白名单或黑名单往往不够用。你需要一套组合策略。推荐的做法是:默认策略设为DROP,然后用富规则精确放行需要的IP和端口,再用单独的富规则封禁已知的恶意IP。这样的好处是,安全基线非常明确——默认全部拒绝,只有明确允许的才能通过。

具体配置顺序建议如下:

# 1. 先设置默认目标为DROP
firewall-cmd --permanent --zone=public --set-target=DROP

# 2. 添加白名单规则(允许特定IP访问特定服务)
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="10.10.10.0/24" port protocol="tcp" port="3306" accept'

# 3. 添加黑名单规则(拒绝恶意IP的所有访问)
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="45.33.32.156" drop'

# 4. 重新加载
firewall-cmd --reload

这里有一个关键点:firewalld的规则是按顺序匹配的,先匹配到的规则优先执行。所以建议把黑名单规则放在白名单规则前面添加,或者利用富规则中的priority参数来控制优先级。不过在大多数场景下,只要白名单和黑名单的IP不重叠,顺序影响不大。

六、使用ipset配合firewalld实现大规模黑白名单

当你需要管理的IP数量达到几百甚至上千个时,一条一条添加富规则就不现实了。这时候可以借助ipset来批量管理。firewalld原生支持ipset,操作方式如下:

第一步,创建一个ipset集合:

firewall-cmd --permanent --new-ipset=blocked_ips --type=hash:ip

第二步,往集合里添加要封禁的IP:

firewall-cmd --permanent --ipset=blocked_ips --add-entry=45.33.32.156
firewall-cmd --permanent --ipset=blocked_ips --add-entry=104.248.50.100

第三步,创建一条引用这个ipset的富规则:

firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source ipset="blocked_ips" drop'

第四步,重新加载:

firewall-cmd --reload

这种方式的优势在于,后续要新增或删除黑名单IP,只需要操作ipset集合,不用动富规则本身。对于动态变化的黑名单来说,这是最高效的方案。

七、富规则的查看、删除和验证方法

配置完成后,一定要验证规则是否正确生效。查看当前zone的所有富规则:

firewall-cmd --zone=public --list-rich-rules

如果你想删除某条特定规则,需要用--remove-rich-rule并指定完全相同的规则字符串:

firewall-cmd --permanent --zone=public --remove-rich-rule='rule family="ipv4" source address="45.33.32.156" drop'

验证规则是否真正生效,可以用nmap从外部扫描,或者直接在另一台机器上telnet测试:

telnet 203.0.113.10 80
telnet 192.0.2.100 22

白名单IP应该能连通,黑名单IP应该直接超时或拒绝连接。另外也可以通过查看内核日志确认drop记录:

journalctl -k | grep BLOCKED_IP

八、常见问题和排错思路

在实际部署中,有几个容易踩的坑需要注意。第一,富规则中的source address如果写错了格式,比如少写了引号或者IP格式不对,命令会报错但不会提示具体哪里错,所以建议先在测试环境验证。第二,如果你同时使用了firewalld和iptables-services,两套规则可能冲突,建议只保留firewalld。第三,zone的选择很重要,public是默认zone,但如果你的服务器有多块网卡或者不同的网络接口,可能需要把规则加到对应的zone里,而不是全部堆在public。

另一个常见问题是,添加了drop规则后发现自己也被锁在外面了。解决办法是通过服务器的控制台(比如云平台的VNC或者物理机的KVM)登录,然后删除或修改那条规则。所以在配置防火墙之前,一定要确保你有带外管理通道,否则一旦配错就可能远程失联。

九、自动化管理黑白名单的实用建议

对于需要长期运营的服务器,建议把黑白名单规则写成脚本或者Ansible playbook,纳入版本管理。比如你可以创建一个shell脚本,每天从某个文件读取IP列表,自动更新ipset集合,然后reload防火墙。这样既能保证规则的可追溯性,也能避免手动操作带来的失误。同时,定期审查规则列表,清理过期的白名单IP和已解除威胁的黑名单IP,保持规则集的精简和高效。

总结一下,CentOS上用firewalld富规则做IP黑白名单,核心就是三步:设定默认DROP策略、用富规则精确放行白名单、用富规则或ipset封禁黑名单。这套方案结构清晰、易于维护、支持动态调整,是当前CentOS环境下最推荐的访问控制实现方式。