ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

银河麒麟V10 SP1 firewalld 命令、富规则与排障实战

银河麒麟V10 SP1 firewalld 命令、富规则与排障实战 1. 先把底摸清银河麒麟 V10 SP1 上的防火墙到底是哪一套在国产化替代的交付现场银河麒麟服务器操作系统 V10 SP1 几乎是绕不开的一环而只要这台机器要对外提供业务防火墙firewalld的指令就一定会被反复翻出来用。我做过的几个项目里服务器上架第一件事往往不是装中间件而是拿着firewall-cmd一条条把端口放通因为连不上、通不了、被拦掉这类问题排查成本远高于提前配好规则。这篇内容就是把我这几年在麒麟服务器上折腾 firewalld 的经验完整摊开从底层机制、区域模型、高频指令、富规则进阶直到排障实录写成一个可以直接照着敲的命令手册兼踩坑记录。它适合三类人刚接手麒麟服务器、对 Linux 防火墙只有模糊印象的新手从 CentOS 7 迁过来、发现命令变了但对不上的老运维以及需要给甲方写交付文档、要求每一步都有依据的集成工程师。我不打算只给你一堆命令列表那样网上一搜一大把我更想讲清楚每条命令背后的判断逻辑以及哪些操作看着没事、实际会在下一次重启或者 reload 之后把你坑到半夜加班。1.1 firewalld 与 iptables 的关系别被两套命令绕晕很多人第一次登进麒麟服务器看到firewalld会本能地想这不就是 iptables 的包装吗我直接iptables -A INPUT不就行了。这个想法在临时实验里没毛病但在生产环境上极其危险。银河麒麟服务器操作系统 V10 SP1 走的是 RHEL 8 / CentOS 8 这一系的技术路线内核里跑的过滤框架是 netfilter而 firewalld 是架在它上面的管理守护进程默认后端在多数版本上是 nftables 而不是老的 iptables。你在命令行敲iptables -L还能看到内容是因为有兼容层把 nftables 的规则翻译给你看但它展示的并不是真相只是视图。更关键的问题在于生命周期。firewalld 有一套自己的规则数据库运行时态和永久态是分开存的firewall-cmd --reload这个动作会把内核里的规则整体清掉、再按自己的数据库重建一遍。你手动塞进去的 iptables 规则不在它的数据库里reload 一执行就全部蒸发。我就遇到过这样的事某次现场为了快速验证同事直接iptables -I INPUT -p tcp --dport 9200 -j ACCEPT当时测通了第二天客户做了一次服务重启端口又封上了排查了半小时才想起来是这条临时规则被冲掉。打个比方更好理解firewalld 是公司前台netfilter 是楼里的门禁主板。你要让访客进来正确做法是去前台登记前台按流程下发权限到主板。你绕过前台直接拆主板接线当下确实能开门但前台每天下班会重新校对所有权限、把没登记的记录清空你接的那根线自然就断了。所以我的习惯很明确只要这台机器装了 firewalld 并且服务是活的就一律用firewall-cmd操作iptables 命令只用来查、不用来改。1.2 三步确认现状别在不知道状态的情况下动手动手之前先做体检这一步花不了两分钟但能省掉后面无数的自我怀疑。第一条命令看系统版本确认你面对的确实是 V10 SP1 还是 SP2、SP3因为不同小版本的 firewalld 包版本会有差异某些参数在低版本上不支持。cat /etc/os-release uname -r第二条命令看服务和版本。注意我这里看的是--version不是-Vfirewalld 的工具参数命名有时候会让人踩坑。systemctl status firewalld firewall-cmd --version firewall-cmd --state--state返回 running 或者 not running简单直接。如果返回 not running先别急着systemctl start得搞清楚它为什么没起来因为有些麒麟的定制镜像在安装阶段就把 firewalld 设成了 disabled替换成了别的安全策略组件也有些场景是前一个运维为了图省事关掉了然后业务就这么裸奔着上线了。这两种情况的处理方式完全不同。第三条命令看后端和当前生效的配置这一步最容易被忽略grep -i -E backend|defaultzone /etc/firewalld/firewalld.conf firewall-cmd --get-default-zone firewall-cmd --get-active-zones firewall-cmd --list-all--get-active-zones的输出值得多看两眼它告诉你每块网卡当前挂在哪个区域上。如果输出里出现的是public而你预期是trusted那后面所有端口明明放通了却连不上的困惑基本就都有答案了。--list-all只显示默认区域的完整规则想看别的区域得加--zone参数这点后面会详细讲。注意不要用systemctl stop firewalld来做关掉试试能不能通的排除法测试。生产机器上关掉防火墙哪怕只有三十秒也等于把整台机器的所有端口暴露出去。正确的验证方式是用临时规则firewall-cmd --add-portxxx/tcp不带 --permanent验证确认没问题再写进永久配置验证完重启一下 firewalld 或者顺手 reload临时规则就自动消失了风险可控得多。1.3 一条命令看全部--list-all-zones 的正确用法新手最常犯的一个错是只在默认区域里折腾然后抱怨规则不生效。真实情况往往是他那台机器有双网卡业务流量从 eth1 进来而 eth1 绑在internal区域上他改的却是public。firewall-cmd --list-all-zones | less firewall-cmd --zoneinternal --list-all--list-all-zones会把九个预置区域全列出来输出很长建议配合less或grep用。我一般会这样快速定位firewall-cmd --list-all-zones | grep -E ^[a-z]|interfaces|sources|ports|services这么一来哪个区域挂着哪块网卡、开了哪些端口一眼就能扫出来。养成先看全局再改局部的习惯能避免绝大多数改了没反应的伪故障。2. 区域模型吃透了规则才不会乱飞firewalld 最反直觉的地方就是区域这个概念。从 iptables 转过来的人习惯想的是入站出站、允许拒绝而 firewalld 的第一层分类是流量属于哪个区域然后才是区域内的允许与拒绝。理解顺序反了配出来的规则就会显得毫无逻辑。2.1 九个预置区域的信任等级与适用场景预置区域本质上是一套按信任度排序的模板集合从最不信任到最信任依次排开。记住这个顺序选区域的时候就不会纠结。区域名默认策略典型使用场景我对它的实际评价drop丢弃所有入站无任何回应暴露在公网且只提供服务端口最狠扫描器连你活着都判断不出来block拒绝所有入站回 icmp 拒绝想明确告诉对方我不接受比 drop 礼貌但会暴露主机存在public放通 ssh、dhcpv6-client 等少数服务单网卡对外服务器最常见的默认值90% 的麒麟服务器出厂就挂这个external放通 ssh默认开启伪装做网关或 NAT 出口的机器当路由器用的机器才需要internal放通 ssh、mdns、dhcpv6 等内网机器之间互访内网办公/测试机常用dmz放通 ssh对外提供服务的隔离区主机安全分区要求高时用work放通 ssh、dhcpv6-client办公终端区域服务器上基本不用home放通 ssh、mdns、samba 等家庭网络服务器上基本不用trusted全部放通完全可信的网段或管理网用起来爽但要想清楚后果我的实际选择习惯是这样的单网卡对外提供业务用public需要什么端口就加什么不去改默认策略管理网段比如堡垒机所在网段单独建一个源地址绑定到trusted这样运维从这里进来不用反复放端口对外的网关机用external配合 masquerade。至于drop和block我用得最多的是拿来当黑名单容器这一点在第 4 章会具体讲。2.2 网卡绑定、源地址绑定与优先级判定流量进来之后firewalld 是按固定顺序决定它属于哪个区域的这个顺序搞不清楚就会出现我在 A 区域开了端口结果走了 B 区域的诡异现象。判定优先级从高到低大致是源地址匹配 入站网卡匹配 默认区域。源地址的优先级最高这是个非常有用的特性。比如你可以这样把管理网段单独拎出来firewall-cmd --permanent --zonetrusted --add-source192.168.30.0/24 firewall-cmd --reload firewall-cmd --zonetrusted --list-sources执行完之后任何源 IP 属于 192.168.30.0/24 的连接无论从哪块网卡进来都会走trusted的全放通策略而其他流量继续走public。这比一条条加端口优雅得多尤其是在运维机 IP 会变动、又有多个人共用一个网段的场景下。这里有个坑必须提前说一个源地址只能属于一个区域。如果你试图把同一个网段加到两个区域firewalld 会直接报ZONE_CONFLICT。如果遇到这个报错先查它现在挂在哪个区域上firewall-cmd --get-active-zones另一种情况是源地址被写进了 IP 集ipset里那么它不会再以一个具体 source 的形式出现在区域列表里需要用--get-ipsets和--info-ipset去找。网卡绑定用的是另一个参数区别在于它按物理入口分类不看源地址firewall-cmd --permanent --zoneinternal --change-interfaceens192 firewall-cmd --reload注意这里是--change-interface不是--add-interface。--add-interface在接口已经绑定到别的区域时会失败而--change-interface是改绑更适合迁移场景。我见过同事用--add-interface反复失败然后怀疑人生其实换成--change-interface一秒解决。2.3 默认区域该改还是该按网卡分绑我的选择逻辑单网卡服务器最简单改默认区域所有规则都在一个地方管排查方便firewall-cmd --set-default-zonepublic这个操作是永久生效的不需要--permanent也不需要 reload因为它改的是配置文件里的默认值。改完用--get-default-zone确认一下。双网卡或者多网卡就不建议改默认区域了而是按业务面分绑。典型场景是一台麒麟服务器既连内网数据库网段又连对外的业务网段这时我会这样规划# 内网网卡绑定到 internal只放通必要端口 firewall-cmd --permanent --zoneinternal --change-interfaceens192 firewall-cmd --permanent --zoneinternal --add-port3306/tcp # 外网网卡绑定到 public只放通业务端口和运维端口 firewall-cmd --permanent --zonepublic --change-interfaceens224 firewall-cmd --permanent --zonepublic --add-port8443/tcp firewall-cmd --reload firewall-cmd --get-active-zones这么配的好处是内网面的端口不会因为某次误操作暴露到外网面上。分区管理带来的心理约束比事后审计要有效得多。坏处是规则分散了所以我会在文档里维护一张网卡—区域—端口的对照表交付时一并给客户省得接手的人一头雾水。提示如果你实在拿不准某块网卡现在挂在哪个区域ip a看清接口名再firewall-cmd --get-active-zones对照两分钟就能理清比反复猜测为什么端口不通高效得多。3. 高频操作端口、服务与规则的增删改查前面两章是地基这一章是真正每天都会用到的部分。我把它按照最常用的动作组织每条命令都配上使用场景和注意点。3.1 开放一个业务端口的标准三连这是出现频率最高的操作标准流程就是三步# 第一步以永久方式添加端口规则 firewall-cmd --zonepublic --add-port8443/tcp --permanent # 第二步重载配置让永久规则进入运行时 firewall-cmd --reload # 第三步验证结果 firewall-cmd --zonepublic --list-ports为什么必须加--permanent因为 firewalld 的规则分两套运行时runtime和永久permanent。不带--permanent的改动只在内存里生效重启服务或者重载就没了带--permanent的改动先写进配置文件但不会立刻生效需要--reload才加载进内核。这个双轨制是新手最容易迷糊的地方我第一次用的时候也被绕了好久。如果只是临时验证比如你想确认某个端口是不是被防火墙拦的那就反着来不加--permanent测完直接重载清干净firewall-cmd --add-port8443/tcp # 验证连通性 firewall-cmd --reload这样操作不会污染配置文件非常干净。我强烈建议所有人都养成先临时验证、再永久落库的习惯它能把实验风险压到最低。端口写法上还有几个细节。TCP 和 UDP 要分别写--add-port53/tcp和--add-port53/udp是两条独立规则。也可以写范围比如--add-port8000-8010/tcp实测很稳用来放通一批连续端口比写十条命令省事。协议除了 tcp/udp还支持 sctp 和 dccp后两者在传统业务里基本用不上但某些电信类业务确实会用到 sctp遇到的时候不用惊讶。3.2 --permanent、--reload 与 --runtime-to-permanent 的区别这几个参数搞混的人特别多我干脆用一张表把它们钉死。命令/参数作用范围是否立即生效是否持久典型使用场合--add-port不加 --permanent运行时是否临时验证、快速排障--add-port加 --permanent配置文件否是正式变更--reload全量重建是不涉及让永久配置生效--complete-reload全量重建并断开连接是不涉及极少数需要彻底清理的场景--runtime-to-permanent运行时转永久不涉及是调了半天运行时规则想一次性落库--complete-reload要单独拎出来说它会重建整个规则集并中断已建立的连接包括你当前的 SSH 会话。我在现场只用过一次是在一条错误的富规则导致所有连接被拒、连日志都看不下去的时候被迫用它把状态全部清干净。日常变更用--reload就够了它不会断掉已建立的连接相对温和。--runtime-to-permanent是我个人非常喜欢的一条命令。场景是这样客户电话里催着要放通某个端口你来不及想清楚要写到哪个区域、要不要加源限制那就先在运行时态快速加几条规则把业务救活等业务稳住了、思路清晰了再一次性--runtime-to-permanent把当前运行时的所有规则落成永久配置然后对着配置文件再整理一遍。这样既不失血过多也不会留下临时隐患。firewall-cmd --runtime-to-permanent执行前建议先--list-all看一眼运行时态里有没有你不想要的东西因为这条命令是无差别地把当前运行时全写下去包括你之前随手加的那些测试规则。3.3 服务名与端口号优先用 service 而不是 port同一个端口你可以写--add-port443/tcp也可以写--add-servicehttps。两者效果一样但语义完全不同。我倾向于优先用服务名理由有三个。第一可读性强。半年后回来看配置--list-services里写着http https mysql谁都看得懂如果是一堆端口号就得逐个去查。第二服务定义里可以包含多个端口和协议比如一个自定义服务可以同时声明 tcp 和 udp 端口一条命令顶两条。第三跨机器迁移时不怕记错端口服务名是稳定的。系统自带的定义放在/usr/lib/firewalld/services/每个服务一个 XML 文件。可以这样查看有哪些可用firewall-cmd --get-services ls /usr/lib/firewalld/services/ | head -20输出是一大串名字用grep筛一下更快比如firewall-cmd --get-services | tr \n | grep -i mysql。如果业务用的是非标准端口、系统里没有对应定义那就自己建一个自定义服务比直接开放端口更规范firewall-cmd --permanent --new-servicemyapp firewall-cmd --permanent --servicemyapp --set-description自研业务服务端口 18080/18081 firewall-cmd --permanent --servicemyapp --add-port18080/tcp firewall-cmd --permanent --servicemyapp --add-port18081/tcp firewall-cmd --reload firewall-cmd --zonepublic --add-servicemyapp --permanent firewall-cmd --reload firewall-cmd --zonepublic --list-services自定义服务的 XML 文件会落在/etc/firewalld/services/下面注意是/etc不是/usr/lib前者是管理员自定义层后者是包管理层的升级时可能被覆盖。这个路径差异在写交付文档的时候一定要写清楚不然客户下次升级系统时你的自定义服务可能会消失。想改或者删掉自定义服务firewall-cmd --permanent --servicemyapp --remove-port18081/tcp firewall-cmd --permanent --delete-servicemyapp--delete-service只对/etc下的自定义服务有效删系统自带的服务会被拒绝这算是 firewalld 的一种保护机制。3.4 批量开放端口与规则清理的实用写法真实项目里经常遇到一次要放通十几个端口的情况一条条敲太慢还容易错。我的做法是先写在纸上或者临时文件里然后用简单的循环批量执行for p in 8080 8081 8082 9000 9001; do firewall-cmd --zonepublic --add-port${p}/tcp --permanent done firewall-cmd --reload firewall-cmd --zonepublic --list-ports清理的时候反过来把--add-port换成--remove-port就行。不过要注意--remove-port对不存在的规则会报错如果你不确定某个端口是否已经开放可以先判断再删或者干脆用2/dev/null忽略报错但我不太推荐忽略报错因为那样你也不知道到底删成功没有实践中更稳的方式是先 list 再决定删哪些。另一个高频动作是清空某个区域的所有规则。这种做法风险很高我从不在生产上对public这么干但如果在测试环境里想回到初始状态可以这样firewall-cmd --zonetest --remove-all-ports --permanent firewall-cmd --zonetest --remove-all-services --permanent firewall-cmd --reload注意这只清端口和服务富规则、转发规则、源地址都不受--remove-all-ports影响得单独处理。很多人以为清完就干净了结果一 list 发现还有一堆 rich rule 挂着所以清完之后一定要再--list-all复核一遍。注意所有涉及删除的操作建议先用--list-all把当前配置截图或者复制下来存一份。我在一次迁移中因为手快删错了一个端口规则又没备份最后是从另一台同配置机器上倒推出来的花了两个小时。从那以后改防火墙前先firewall-cmd --list-all /tmp/fw-$(date %F-%H%M).txt成了我的肌肉记忆。4. 富规则进阶黑白名单、限速与日志一把抓基础的端口放通能满足八成场景剩下两成比如只允许某几个 IP 访问数据库端口某个 IP 一直在爆破 SSH 要封掉要记录被拒绝的连接就得靠富规则rich rule。富规则是 firewalld 里表达力最强的部分也是语法最容易写错的部分。4.1 富规则语法结构拆解与三个真实例子富规则的完整结构可以拆成几段来看rule开头后面跟family指定 IPv4 还是 IPv6然后是source或destination限定地址接着是要匹配的元素端口、服务、协议等再往后是可选的动作修饰log、audit、limit最后是accept、reject或drop三个动作之一。语法里引号和等号的位置很讲究写错了会直接报INVALID_RULE。第一个例子只允许特定网段访问 SSH其他一律拒绝。这个用法在安全加固里非常常见firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address192.168.30.0/24 port port22 protocoltcp accept firewall-cmd --reload注意这里我只写了 accept没有写 reject。原因是 firewalld 区域本身有默认策略public区域默认拒绝未明确放通的东西所以不需要额外写 reject。如果你写了两条反而容易因为顺序问题产生意外结果。第二个例子封禁一个具体 IP 的全部访问firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address203.0.113.45 drop firewall-cmd --reload用drop而不是reject是因为drop直接丢弃报文、不给任何回应对方只能等到超时扫描工具判定不出主机是否存活而reject会回一个拒绝报文等于告诉对方我在但我不让你进。安全场景下我更倾向drop。第三个例子拒绝的同时记录日志方便事后分析firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address198.51.100.0/24 log prefixBLOCKED-198 levelwarning drop firewall-cmd --reload日志会进系统日志用journalctl -f或者看/var/log/messages就能看到prefix是一个自己起的标记方便 grep。这个技巧在排查到底是谁在扫我时特别有用。4.2 用 ipset 做批量黑名单比一条条写富规则优雅得多如果要封的 IP 有几十上百个一条条写富规则既难看又难维护。这时候用 ipset它就是专门干这个的。思路是先把 IP 装进一个集合再让区域引用这个集合。# 创建集合 firewall-cmd --permanent --new-ipsetblacklist --typehash:ip firewall-cmd --reload # 往集合里加 IP firewall-cmd --permanent --ipsetblacklist --add-entry203.0.113.45 firewall-cmd --permanent --ipsetblacklist --add-entry203.0.113.46 firewall-cmd --permanent --ipsetblacklist --add-entry198.51.100.0/24 # 把集合挂到 drop 区域实现静默丢弃 firewall-cmd --permanent --zonedrop --add-sourceipset:blacklist firewall-cmd --reload为什么挂到drop区域而不是在public里写富规则因为drop区域的默认策略就是丢弃一切IP 一旦被划进这个区域不管它想访问哪个端口都会被静默处理等于一个全局封禁。这比逐端口写拒绝规则覆盖面广得多也更容易维护。查集合内容用这条firewall-cmd --permanent --ipsetblacklist --get-entries firewall-cmd --get-ipsets集合的持久化文件放在/etc/firewalld/ipsets/下面格式是 XML备份的时候别忘了这个目录。关于drop和reject的取舍我的经验是这样对付扫描和爆破用drop因为不给回应能降低被进一步盯上的概率但如果是内网业务互访被拦用reject更好因为被拒方会立刻收到明确反馈排查起来快不至于让人对着超时发呆。4.3 用富规则做限速缓解 SSH 爆破压力限速是富规则里被低估的能力。比如 SSH 端口暴露在公网的机器每天被爆破是常态用limit参数可以在防火墙层就把频率压下来firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 port port22 protocoltcp limit value10/m accept firewall-cmd --reload这条规则的含义是每分钟最多接受 10 个新建连接到 22 端口超出的会被拒绝。对于正常的运维登录来说每分钟 10 次绰绰有余对于爆破脚本来说这个速度基本没法在合理时间内试出密码。需要注意limit的粒度是全局的不是按源 IP 分别计数的。也就是说如果有很多人同时登录可能会误伤。更精确的做法是配合 ipset 或者按源网段分别限速但配置复杂度会明显上升。我的建议是公网暴露的 SSH 端口先上全局限速能挡掉绝大部分自动化爆破如果确实有大量并发登录需求考虑把 SSH 挪到非标端口配合密钥登录防火墙层只管放通和封禁。限速还有个细节value的写法支持N/s、N/m、N/h、N/d四种单位分别是每秒、每分、每小时、每天。写10/m比写0.16/s直观得多建议统一用分钟做单位。4.4 端口转发与地址伪装网关场景必备如果这台麒麟服务器要当网关或者做反向代理的前置端口转发就会用得上。做转发之前先确认内核转发参数是开着的sysctl -w net.ipv4.ip_forward1 echo net.ipv4.ip_forward 1 /etc/sysctl.d/99-forward.conf然后配置伪装masquerade这是做 NAT 的必要条件firewall-cmd --permanent --zonepublic --add-masquerade最后配端口转发把外部访问 80 端口的流量转到内网某台机器的 8080 上firewall-cmd --permanent --zonepublic --add-forward-portport80:prototcp:toport8080:toaddr192.168.10.20 firewall-cmd --reload firewall-cmd --zonepublic --list-forward-ports这里的参数顺序很容易记反我的记法是从哪来port/proto→ 到哪去toport/toaddr先写源侧后写目标侧。如果只写toport不写toaddr那就是本机端口之间的跳转比如把 80 转到本机的 8080这种用法在做非 root 运行的服务时挺常见。有个坑要提醒转发规则生效的前提是目标端口或者流量路径上没有被防火墙拦住。我遇到过一次配了转发但一直不通检查半天发现内网那台机器自己的 firewalld 没放通 8080。防火墙是链式的一台通了不代表通两端都得放。5. 图形化、备份与其它组件的配合命令行的东西讲完了但真实交付里还有几个绕不开的话题图形界面工具要不要用、配置怎么备份迁移、以及 firewalld 和网络管理、容器组件之间那些微妙的相互影响。5.1 firewall-config 图形界面到底值不值得用firewall-config是 firewalld 的官方图形客户端麒麟服务器带桌面环境的话可以直接调起来。它的优点是直观区域、服务、端口、富规则都做成了可视化面板改完点一下重新加载就生效适合对命令不熟的人快速上手。但我个人的立场是服务器上尽量用命令行图形界面只在两种情况下用。一是给别人演示结构可视化面板能让人一眼看懂区域—服务—端口的层次关系比讲解半小时有效二是紧急排障时想快速浏览全部区域配置图形界面的一栏式展示比命令输出好找。正式变更不用它的原因有三个。第一图形界面操作很难留下可审计的命令记录出了问题追溯不到具体改了什么。第二它依赖桌面环境和 dbus通过 SSH 转发 X11 用起来很别扭延迟也高。第三某些低版本上图形界面和命令行状态同步会有延迟你以为保存了其实没生效。相比之下命令行改完--reload一执行--list-all一验证路径清晰、可复现。5.2 配置文件结构解析与备份迁移的正确姿势firewalld 的所有永久配置都躺在/etc/firewalld/下面理解这个目录结构备份和迁移就有了章法。路径存的是什么迁移时是否要带/etc/firewalld/firewalld.conf全局配置默认区域、后端类型、日志开关要带但注意后端差异/etc/firewalld/zones/各个区域的 XML 定义要带/etc/firewalld/services/自定义服务的 XML要带/etc/firewalld/ipsets/自定义 IP 集合要带/etc/firewalld/helpers/协议助手定义用到了才带/usr/lib/firewalld/系统自带的区域和服务定义不要带跟随系统包备份一条命令就够tar -zcvf /root/firewalld-backup-$(date %F).tar.gz /etc/firewalld恢复的时候最稳的做法是先把新机器上的 firewalld 停掉或者至少确认没有运行时改动会被覆盖解压覆盖然后重载systemctl stop firewalld tar -zxvf /root/firewalld-backup-2024-06-01.tar.gz -C / systemctl start firewalld firewall-cmd --list-all-zones跨机器迁移有个必须注意的点区域里绑定的网卡名一定要核对。源机器上可能叫ens33目标机器上叫ens160直接恢复过去会导致接口绑定全部失效规则看起来在但流量走的还是默认区域。恢复完务必用--get-active-zones检查并重新绑定接口。提示如果目标机器是离线环境恢复流程还有个额外麻烦就是某些自定义服务依赖的 XML schema 版本可能和系统自带的 firewalld 版本不匹配重载时报错。稳妥做法是先在测试机上验证一遍恢复流程确认无误再去现场操作。5.3 和 NetworkManager、容器组件的那些微妙关系firewalld 和 NetworkManager 是联动的NetworkManager 在管理网卡连接时会去问 firewalld这块网卡该挂哪个区域而默认区域的设置会影响这个判断。所以如果你同时改了 NetworkManager 的连接配置和 firewalld 的区域绑定两边打架是可以预见的。我的处理原则是网卡的区域归属只在 firewalld 里配不去 NetworkManager 里重复设置避免两处配置来源不一致。容器这块要单独说。Docker 这类运行时在启动容器、做端口映射时会直接写底层转发规则绕过 firewalld 的管理层。结果就是一个很迷惑的现象容器映射的端口即使 firewalld 里没有放通外部也能访问。很多人因此认为firewalld 对容器无效但其实不是无效是路径被绕过了。这带来两方面的隐患。安全上你可能以为端口被防火墙保护着实际上容器一跑就全暴露了。运维上你写的 firewalld 规则对容器流量不生效改来改去很挫败。我的应对方式有两种看场景选一是把容器端口映射绑定到具体的内网地址上比如只映射到 127.0.0.1 或内网网卡从源头上限制暴露面二是把容器的转发链显式纳入 firewalld 的管控范围配置相对复杂但管控更彻底。不管选哪种都要在部署文档里写清楚别让接手的人以为 firewalld 规则是唯一防线。还有一类组件会碰到防火墙就是需要动态端口或者大量随机端口的服务比如某些集群通信组件。这种场景下用固定端口范围去放通往往不现实我的做法是给这类组件单独划分一个区域把相关网段加进去然后用trusted把开放面限制在可控的网段内而不是无脑全放。6. 排障实录那些年踩过的坑前面都是怎么配这一章讲配了不通怎么办。我把这些年遇到的问题整理成速查表再加上几条通用排查思路。6.1 现象—原因—解决速查表现象最可能的原因快速验证与解决加了端口但连不上只加了运行时没加 --permanent或是没 reloadfirewall-cmd --list-ports看不到就是没生效reload 之后规则消失了加规则时没带 --permanent重新加并带 --permanent或先 --runtime-to-permanent端口放通了但重启后又断同上写在了运行时检查--permanent --list-ports改了默认区域但没变化网卡单独绑了别的区域优先级更高firewall-cmd --get-active-zones看实际归属富规则报 INVALID_RULE引号缺失、参数顺序错、family 没写单独拆开测试先不加 log 和 limit同一个源加到两个区域报 ZONE_CONFLICT源地址只能属于一个区域先从原区域 remove-source 再加容器端口没放通也能访问容器运行时绕过 firewalld检查端口映射的绑定地址或改用受限地址规则在但服务连不上目标机自己的防火墙没放通两端都查链路是逐跳生效的日志里看不到拒绝记录默认不记录被拒连接用--set-log-deniedall或加 log 富规则修改后 SSH 断了用了 --complete-reload 或者误删了 SSH 规则提前保留一条 SSH 放通规则别动它这张表里最值得强调的是第一条。我统计过自己遇到过的防火墙故障超过一半实际上是规则没生效而不是规则写错了。所以排查顺序永远是先确认规则在不在再确认规则对不对最后才怀疑是不是别的原因。6.2 三条通用排查思路按顺序来第一条从 firewalld 自身状态往上查。firewall-cmd --state看服务活没活--get-active-zones看流量走的是哪个区域--zonexxx --list-all看这个区域到底放通了什么。这三步能解决大部分疑问。firewall-cmd --state firewall-cmd --get-active-zones firewall-cmd --list-all-zones | grep -A5 public第二条打开拒绝日志看看到底有没有被拦。默认情况下 firewalld 不记录被拒绝的连接这导致你只能看到不通但看不到为什么不通。临时打开日志firewall-cmd --set-log-deniedall journalctl -f -u firewalld--set-log-denied有几个取值all记录所有被拒unicast只记录单播broadcast只记录广播multicast只记录组播off关闭。排查阶段用all查完记得改回off不然日志会被刷爆生产机器上磁盘写满可不是小事。第三条用ss和tcpdump交叉验证判断问题到底在防火墙还是服务本身。这一步很关键能帮你避免在防火墙上白费功夫。ss -lntp | grep 8443 tcpdump -i any -nn port 8443 -c 20如果ss显示没有进程监听这个端口那问题根本不在防火墙是服务没起来。如果tcpdump能看到 SYN 包进来了但没有 SYN-ACK 回去而服务确实在监听那才基本可以确定是防火墙或者路由层面拦掉了。这个判断逻辑我用了很多年屡试不爽。6.3 别把 SELinux 的锅甩给防火墙有一个特别隐蔽的坑端口放通了、服务在监听、tcpdump也能看到包进来但连接就是被拒或者服务表现为异常。这种情况很可能是 SELinux不是 firewalld。SELinux 管的是进程能不能监听某个端口和防火墙管的是外部能不能进来是两个维度的事。默认策略下只有被允许的端口类型才能被服务绑定你把服务换到非标端口上即使防火墙放通了SELinux 也可能直接拒绝绑定。验证和临时放开的方式getenforce semanage port -l | grep http_port_t semanage port -a -t http_port_t -p tcp 18080需要说明的是这两个命令是给非标端口申请许可属于安全策略调整改动前应该评估影响别当成常规操作随手敲。更稳妥的做法是尽量使用系统默认允许的端口类型把端口变更降级成只改防火墙避免引入 SELinux 这一层复杂度。我在项目里见过有人为了一个端口折腾了半天最后发现是 SELinux 的原因而他从头到尾都没往这个方向想过一次。7. 交付前的收尾动作与我个人的操作习惯变更做完不等于结束收尾的几分钟决定了这次改动会不会在半夜变成一通电话。7.1 上线前的检查清单我给自己定了一份固定动作每次改完防火墙都会走一遍你可以直接抄# 1. 看默认区域和实际归属 firewall-cmd --get-default-zone firewall-cmd --get-active-zones # 2. 看全部区域的完整配置重点看 public / internal firewall-cmd --list-all-zones /tmp/fw-final-$(date %F-%H%M).txt # 3. 看永久配置和运行时是否一致 firewall-cmd --permanent --list-all firewall-cmd --list-all # 4. 看转发和伪装 firewall-cmd --list-forward-ports firewall-cmd --query-masquerade # 5. 备份配置 tar -zcvf /root/firewalld-$(date %F).tar.gz /etc/firewalld第 3 步特别重要。运行时不等于永久这是 firewalld 的核心特性也是事故的高发地带。如果两边不一致说明你的改动还没落库重启就丢。养成对比的习惯能提前拦住这类问题。还有一件事容易忘确认 SSH 的放通规则完好。我有一次整理区域规则时差点把 22 端口的规则删掉好在--list-all复核时看到了。从那以后我改规则前会先单独确认一遍 SSHfirewall-cmd --zonepublic --query-servicessh返回 yes 才动手返回 no 就先补上再说。7.2 我个人的几条习惯供你参考第一条变更前先记录变更后再记录中间过程用临时规则过渡。这听起来啰嗦但每次事故之后复盘问题几乎都出在没记录和图省事直接改永久这两点上。第二条永远不用systemctl stop firewalld来测试。前面已经说过但值得再说一遍因为它太常见了。用临时规则验证代价几乎为零风险也几乎为零。第三条规则要写注释注释要写在文档里而不是命令里。firewalld 的富规则不支持注释语法所以我会在交付文档里维护一张规则表写清楚每条规则是给谁用的、什么时候加的、什么时候可以删。有了这张表半年后接手的人不用猜。第四条能限定源就不放开源。同城的一个端口加个源地址限制安全性的提升是指数级的。很多端口其实只需要特定网段能访问但图省事写成了全放通这种债迟早要还。第五条把限速和日志当成默认动作。公网暴露的任何端口我都会顺手加一条限速规则被拒连接的日志开关在排查期打开稳定后关掉。这两件事加起来花不了五分钟但能在真正出事的时候给你留下证据链。最后再分享一个我自己常用的技巧把日常最高频的五六条命令写成一个 shell 脚本叫fwshow.sh内容就是--get-active-zones、--list-all、--list-forward-ports这几条串起来放在/root/bin下面。每次登进一台不熟悉的麒麟服务器先跑一遍这个脚本三十秒之内就能对这台机器的防火墙状态心里有数。这比每次凭记忆敲五条命令快也避免了漏看某一项。工具本身很简单但它把先摸清现状再动手这个原则变成了一个不用思考的动作长期来看省下的时间相当可观。
返回列表