在CentOS 7及以上版本中,firewalld取代了传统的iptables成为默认防火墙管理工具,而ipsets则是firewalld底层用来高效管理大量IP黑名单的核心组件。所谓"富规则"(Rich Rules),是firewalld提供的一种比简单端口/服务规则更灵活的配置方式,它允许你针对特定源IP、目的IP、端口、协议、动作等进行精细组合控制。而ipsets黑名单机制,则是将成百上千甚至数万个恶意IP地址归入一个集合,firewalld通过引用这个集合一次性拒绝所有来自该集合的流量,性能极高、管理方便。这篇文章直接告诉你怎么配、怎么用、怎么优化,不绕弯子。

一、firewalld富规则到底是什么,为什么要用它

firewalld的规则体系分为几个层级:最简单的是直接开放某个服务(比如--add-service=http),稍微复杂一点是开放某个端口(--add-port=8080/tcp),但这些都不够精细。富规则(Rich Rule)的出现就是为了解决"我只想让某个特定IP访问某个特定端口,其他全部拒绝"这类需求。

富规则的语法结构是这样的:

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.100" port protocol="tcp" port="3306" accept'

这条规则的意思是:永久添加一条富规则,允许来自192.168.1.100这个IP的TCP协议访问3306端口。你可以把source换成任何IP段,把port换成任何端口,把accept换成drop或reject,组合非常自由。

富规则相比普通规则的核心优势在于三点:第一,它支持源地址和目的地址的精确指定;第二,它支持协议、端口、动作的任意组合;第三,它可以设置优先级(priority参数),当多条规则冲突时,优先级高的先匹配。实际运维中,富规则是处理"白名单IP访问特定服务"场景的首选方案。

二、ipsets黑名单机制的工作原理

ipsets是Linux内核层面的一个扩展模块,它的作用是把大量IP地址、端口、网络等元素组织成一个"集合"(set)。firewalld可以直接引用这个集合作为规则的源或目的,从而实现批量封禁。

为什么不直接用firewalld的rich rule一条一条加IP?因为当你要封禁5000个恶意IP时,写5000条rich rule会让防火墙规则链变得极其臃肿,匹配效率急剧下降。而ipsets把这些IP放进一个哈希表结构的集合里,内核在匹配时是O(1)复杂度,性能几乎不受IP数量影响。

ipsets的类型有很多,常用的包括:hash:ip(存储单个IP)、hash:net(存储网段)、hash:ip,port(存储IP+端口组合)、list:set(可以嵌套其他集合)。对于纯IP黑名单场景,hash:ip是最合适的选择。

三、从零开始配置ipsets黑名单

第一步,创建一个名为blacklist的ipsets集合,类型为hash:ip:

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

第二步,往集合里添加恶意IP:

firewall-cmd --permanent --ipset=blacklist --add-entry=203.0.113.50
firewall-cmd --permanent --ipset=blacklist --add-entry=198.51.100.23
firewall-cmd --permanent --ipset=blacklist --add-entry=192.0.2.100

第三步,也是最关键的一步,创建一条富规则引用这个ipsets集合,将所有来自该集合的流量丢弃:

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source ipset="blacklist" drop'

第四步,重新加载防火墙使配置生效:

firewall-cmd --reload

到这里,所有在blacklist集合中的IP发出的流量都会被直接丢弃。你可以随时往集合里加IP,也可以删除:

firewall-cmd --permanent --ipset=blacklist --remove-entry=203.0.113.50

四、富规则与ipsets结合的高级用法

实际生产环境中,单纯的"全部丢弃"有时候太粗暴。你可能需要更精细的策略,比如:只丢弃黑名单IP对SSH端口的访问,但允许它们访问HTTP服务(用于蜜罐或日志收集)。这时候富规则的灵活性就体现出来了:

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source ipset="blacklist" port protocol="tcp" port="22" drop'

这条规则只针对黑名单IP的22端口做丢弃,其他端口不受影响。你还可以叠加多条规则,比如再加一条允许黑名单IP访问80端口用于记录行为:

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source ipset="blacklist" port protocol="tcp" port="80" accept'

注意规则的优先级问题。firewalld的富规则默认优先级为0,数值越小优先级越高。如果你希望某条规则优先匹配,可以显式指定:

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source ipset="blacklist" port protocol="tcp" port="22" drop priority="10"'

另外,ipsets还支持从文件批量导入。你可以先把所有恶意IP写到一个文本文件里,每行一个IP,然后用以下命令批量导入:

firewall-cmd --permanent --ipset=blacklist --add-entries-from-file=/etc/firewalld/ipsets/blacklist.txt

这个功能在处理大规模黑名单时非常实用,比如从威胁情报平台下载的IP列表,直接导入即可。

五、查看和验证配置是否生效

配置完之后,务必验证。查看当前所有ipsets集合:

firewall-cmd --list-ipsets

查看某个集合里的具体IP:

firewall-cmd --ipset=blacklist --get-entries

查看所有富规则:

firewall-cmd --list-rich-rules

如果你想确认某条规则是否真正在生效,可以用nftables或iptables查看底层规则(firewalld在CentOS 8+默认使用nftables作为后端):

nft list ruleset | grep blacklist

你会看到类似这样的输出,证明ipsets集合已经被正确引用到规则链中:

ip saddr @blacklist tcp dport 22 drop

六、性能优化与注意事项

ipsets的性能优势在IP数量超过几百个时才明显体现。如果你只有十几个IP要封,直接用rich rule就够了,没必要建ipsets。一般建议当黑名单超过200个IP时,切换到ipsets方案。

另外要注意,ipsets是永久存储在内存中的,服务器重启不会丢失,但如果你用--permanent添加的规则没有执行reload,重启后也不会生效。所以养成习惯:每次修改完都执行firewall-cmd --reload。

还有一个容易忽略的点:firewalld的zone概念。ipsets和富规则都是绑定在特定zone上的(默认是public zone)。如果你有多个zone,记得在正确的zone上操作,或者用--zone=参数指定:

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

最后,定期清理过期的黑名单IP也很重要。威胁情报是有时效性的,三个月前的恶意IP可能已经不再活跃。建议写一个定时脚本,定期从情报源拉取最新列表,替换掉旧的集合内容。

七、完整实战示例:构建一个生产级防护方案

假设你是一台对外提供Web服务的CentOS服务器,需要:只允许办公网段访问管理端口,封禁已知恶意IP对所有服务的访问。完整操作如下:

# 1. 创建黑名单ipsets
firewall-cmd --permanent --new-ipset=malicious_ips --type=hash:ip

# 2. 从文件批量导入恶意IP
firewall-cmd --permanent --ipset=malicious_ips --add-entries-from-file=/opt/security/malicious_ips.txt

# 3. 封禁黑名单IP的所有入站流量
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source ipset="malicious_ips" drop'

# 4. 只允许办公网段访问SSH
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.10.0.0/16" port protocol="tcp" port="22" accept'

# 5. 开放HTTP和HTTPS给所有人
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https

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

# 7. 验证
firewall-cmd --list-all

这套方案兼顾了安全性和可用性,既不会误封正常用户,又能高效拦截已知威胁。ipsets负责大规模黑名单的高效匹配,富规则负责精细化的访问控制,两者配合是CentOS防火墙配置的最佳实践。

八、常见问题排查

如果配置后发现规则没有生效,先检查几个点:是否加了--permanent参数?是否执行了--reload?zone是否正确?可以用firewall-cmd --list-all查看当前所有生效规则,确认ipsets和rich rules都在列表中。如果还是不行,检查SELinux状态,有时候SELinux会阻止firewalld正常加载ipsets模块,临时关闭测试一下:setenforce 0。

总结一下:firewalld的富规则提供了细粒度的流量控制能力,ipsets提供了大规模IP集合的高效管理能力,两者结合使用是CentOS服务器安全防护的核心手段。掌握这套组合拳,基本能应对绝大多数入侵防护场景。