ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

firewalld防火墙配置实战:zone机制、端口转发与排查技巧

firewalld防火墙配置实战:zone机制、端口转发与排查技巧 刚做完一批 Linux 服务器的安全加固其中一台业务机器就栽在防火墙规则上明明按文档放通了 8080 端口可外部就是访问不了排查到最后发现是 firewalld 的 zone 理解错了规则写到了默认 zone而实际流量走的是另一个 zone。像这类问题在实际运维中非常典型而大部分新人卡住的原因不是命令记不住而是没搞懂 firewalld 这套“区域服务运行时/持久化”的设计逻辑。这篇文章我就以自己的实操经验为主线把第 15 章“防火墙配置firewalld”从头到尾拆开讲清楚内容包括firewalld 的设计思路、zone 的用法、日常增删改查命令、NAT 与端口转发、图形化工具、配置持久化以及我踩过的坑和对应的排查方法。无论你是刚接触 Linux 运维的新手还是被 firewalld 规则折腾过的老手这篇文章都值得收藏备用。1. 理解 firewalld 的设计逻辑zone、runtime 与 permanent 到底是怎么回事1.1 zone区域不是安全等级而是“网络信任边界”很多新手第一次看到 firewalld 的 zone 列表都会懵public、trusted、internal、dmz、work、home——这些名字看起来像安全等级但实际含义是“对某个网络连接的信任程度”。public默认认为网络里的其他主机都不可信而trusted则完全信任网段内的所有主机。这套设计借鉴了企业网络把交换机端口划分到不同 VLAN 的思路只不过 firewalld 把它搬到了主机内部。默认情况下firewalld 把网卡分配到publiczone整台服务器只会放行很少的端口通常是 ssh 和 dhcp 客户端。在配置前我建议先运行下面这条命令看看当前所有 zone 的配置全局面貌firewall-cmd --get-default-zone firewall-cmd --list-all-zones把两台都跑起来对比输出你会发现每个 zone 的services、ports和masquerade状态都不一样。理解好 zone 并且养成“想清楚流量该进哪个 zone 再动手”的习惯后面写规则就不容易乱。1.2 runtime 与 permanent临时规则和永久规则的边界firewalld 有两个“配置面”runtime运行中的配置和 permanent永久配置。直接用firewall-cmd --add-port8080/tcp修改的是 runtime机器重启或执行firewall-cmd --reload后就会丢失。要写入永久配置必须加--permanent参数。实际运维中建议遵循“先临时放通验证再写入永久配置”的顺序。比如新上线一个 Web 服务先用--add-port80/tcp临时放通确认页面访问正常后再执行--runtime-to-permanent一条命令把当前 runtime 配置全部固化干净又避免重复敲命令。如果临时验证失败直接--reload就能把规则全部撤掉不会留下垃圾规则。1.3 为什么内核里有 iptables 还要用 firewalldfirewalld 本质上是一个管理 netfilter 规则的前端服务它通过调用nftables或老的iptables后端来实现数据包过滤。它带来的最大价值是把底层链式规则的复杂度封装成了“zone service rich rule”这种相对好理解的语言。举个例子你想放行 MySQL 的 3306 端口。纯 iptables 需要写iptables -A INPUT -p tcp --dport 3306 -j ACCEPT在 firewalld 里你只要firewall-cmd --permanent --add-servicemysql firewall-cmd --reload后者还自动帮你处理了重载时的规则衔接问题——firewalld 的规则变更是在运行时热加载的不像 iptables 那样容易被粗暴刷掉。理解这层关系你就不会在“明明改了规则却不生效”这个问题上浪费太多时间。2. 基础配置实操从查状态到放行端口一步步搭起你的访问规则2.1 先搞清楚服务状态和当前规则动手前先确认 firewalld 到底在不在跑状态输出里Active: active (running)和running缺一不可systemctl status firewalld firewall-cmd --state如果输出not running先启动并设置开机自启systemctl enable --now firewalld日常检查规则集最常用的是firewall-cmd --list-all这条命令会展示当前默认 zone、放行的服务列表、端口列表、伪装状态和富规则。如果觉得不够直观可以加--zonedmz --list-all查看指定 zone 的完整规则。我一般会在改规则之前先执行一次把规则快照留在终端里方便后面滚动对比。2.2 放行服务与端口--add-service和--add-port的选择firewalld 预定义了很多服务名位于/usr/lib/firewalld/services/目录每个服务对应一个 XML 文件。比如http服务对应放行 80/tcphttps对应 443/tcpmysql对应 3306/tcp。使用服务名的好处是你不用记住每个应用的端口号而且服务变更时只需改一个地方。查看系统支持哪些服务firewall-cmd --get-services但如果服务没有预定义比如某个私有应用的端口是 9000就直接按端口放行firewall-cmd --permanent --add-port9000/tcp firewall-cmd --reload这里有一个新手特别容易踩的坑只写了端口号没写协议。firewalld 的端口规则必须指明tcp或udp写成--add-port9000会直接报错。另外放行 UDP 时要格外谨慎——UDP 没有连接状态规则一旦放错攻击面会比 TCP 大得多。2.3 移除规则的两种姿势--remove与--remove-service清理规则用--remove-port或--remove-service要跟添加时的写法完全对应firewall-cmd --permanent --remove-port9000/tcp firewall-cmd --permanent --remove-servicehttp如果临时移除不加--permanent这样 reload 后规则又回来了。很多文档没写这一点导致有人用--remove-port删了端口reload 后端口又神奇地放开了误以为是没生效。其实就是 runtime 和 permanent 的区别没搞透。2.4 把某网段或网卡绑定到指定 zone不同网段走不同信任策略是 zone 的核心能力。比如把内网网卡ens160绑定到internalzone把外网网卡ens192绑定到publiczonefirewall-cmd --permanent --zoneinternal --change-interfaceens160 firewall-cmd --permanent --zonepublic --change-interfaceens192 firewall-cmd --reload绑定后内网访问者默认就能获得internalzone 里放行的服务公共 zone 的规则只影响外网访问。这里建议先用firewall-cmd --get-active-zones确认绑定结果再做下一步。2.5 配置永久生效的完整套路下面是一条完整的操作链路供直接抄作业。场景服务器有两个网卡内网走internal公网走public需要放行 8080 端口给业务、放行 443 给 HTTPS同时限制公网只能访问 443# 1. 查看当前状态 systemctl status firewalld # 2. 绑定网卡到 zone firewall-cmd --permanent --zoneinternal --change-interfaceens160 firewall-cmd --permanent --zonepublic --change-interfaceens192 # 3. internal 放行 8080 和 http firewall-cmd --permanent --zoneinternal --add-port8080/tcp firewall-cmd --permanent --zoneinternal --add-servicehttp # 4. public 只放行 https firewall-cmd --permanent --zonepublic --add-servicehttps # 5. 重载生效 firewall-cmd --reload # 6. 验证 firewall-cmd --zoneinternal --list-all firewall-cmd --zonepublic --list-all这套流程走下来既完成了需求又保证了最小权限是生产环境的标准姿势。3. 富规则与高级配置按来源 IP、协议做精细化管控3.1 为什么需要富规则单纯的 service 和 port 只能按“目标端口”放行做不到“只允许某个 IP 访问某个端口”。比如一台数据库服务器只希望办公网段的192.168.10.0/24能连 3306其他 IP 一律拒绝。这种需求用富规则rich rule就能精确控制而且语法看着复杂实际拆解后非常简单。3.2 富规则的完整语法拆解通用格式如下firewall-cmd [--zonezone] --add-rich-rulerule [familyipv4|ipv6] [source addressIP或网段 [inverttrue|false]] [destination addressIP或网段] service name服务名 | port port端口 protocol协议 [log [prefix日志前缀] [level日志级别]] [audit] [accept|reject|drop|mark] 这个语法不难记只要抓住几个关键点rule开头然后指定source、destination接着写service或port最后是动作accept/drop/reject。family 表示 IP 协议族只在桥接等特殊场景下必须显式设置常规 IPv4 环境不写也行。3.3 实际场景只允许办公网段访问 SSH比如把 SSH 从默认 22 改到 22022同时只允许10.0.0.0/8访问firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address10.0.0.0/8 port port22022 protocoltcp accept firewall-cmd --reload注意顺序drop和accept的求值顺序与规则写入顺序有关firewalld 会按规则的从前往后顺序匹配后写的规则优先。实际配置时我会把“允许”规则写在“拒绝”规则之前避免被更早的拒绝规则提前命中。3.4 富规则优先级和与普通规则的配合富规则的优先级高于普通--add-port规则。也就是说即使你先放行了 3306 端口后面又写了一条来源为10.0.0.0/8拒绝访问 3306 的富规则后者也会优先生效。这给工作带来的启示是不要让富规则和简单端口规则表达互相矛盾的意图尽量把同类策略集中到同一种规则类型中否则排障时会很痛苦。富规则还支持日志记录比如要记录来自某个 IP 的所有被拒绝的 SSH 尝试firewall-cmd --permanent --add-rich-rulerule familyipv4 source address192.168.1.100 service namessh log prefixSSH_BLOCK: levelinfo drop日志会打到系统的/var/log/messages配合journalctl -f可以实时观察攻击来源。4. NAT、端口转发与伪装让 firewalld 帮你做流量跳板4.1 masquerade伪装到底解决什么问题内网机器想通过这台服务器上网或者想让外部访问内网服务核心是两个字转发。firewalld 里打开masquerade就是开启源地址伪装效果类似 iptables 的SNAT它会把从这里出去的所有数据包的源 IP 改写成这台服务器的出口 IP。在企业场景里这很常见一台 Linux 服务器作为网关内网网段172.16.1.0/24的机器把默认网关指到这台服务器然后服务器上执行firewall-cmd --permanent --zoneinternal --add-masquerade firewall-cmd --reload别忘了开启内核转发sysctl -w net.ipv4.ip_forward1 echo net.ipv4.ip_forward 1 /etc/sysctl.conf很多人以为开了 masquerade 就能转发实际上内核转发参数不开包根本不会往上层走只是被丢弃。这个顺序问题至少坑过我三次务必记住。4.2 forward-port把公网端口映射到内网主机端口转发port forwarding是 NAT 的核心能力。比如内网有台 Web 服务器 IP 是192.168.1.10你想让外网通过这台防火墙的 8080 端口访问它配置如下firewall-cmd --permanent --zonepublic --add-forward-portport8080:prototcp:toport80:toaddr192.168.1.10 firewall-cmd --reload语法拆解port是外网监听端口proto是协议toport是内网目标端口toaddr是内网目标 IP。如果只想转发到本地端口比如本机 80 转发到 8080toaddr可以省略。这条命令在网络模拟器环境里尤其常用——比如通过 ensp 搭了一套企业网络拓扑核心交换机负责三层转发但最终要对外发布的业务服务器上一样跑着 firewalld 做端口映射。很多网络工程师习惯只在路由器上做 NAT实际生产环境里很多场景是防火墙服务器配合硬件防火墙一起完成内外网交付的。再补充一个关键点--add-forward-port并不会自动开启 masquerade但在某些场景下需要配合开启。如果目的地址在本机端口转发到本机其他服务不需要 masquerade。如果转发到内网其他机器则建议同时开启 masquerade否则回程包可能因为路由问题丢失。我踩过一次转发配置完全正确但客户端一直超时最后在防火墙上抓包才发现回包根本没回到这台机器上。搭配永久配置的完整示例firewall-cmd --permanent --zonepublic --add-servicehttps firewall-cmd --permanent --zonepublic --add-forward-portport8443:prototcp:toport443:toaddr192.168.1.10 firewall-cmd --permanent --zonepublic --add-masquerade firewall-cmd --reload4.3 HTTP/HTTPS 反向代理与端口转发的选型思路有些场景里你其实不一定需要 firewalld 的端口转发。比如应用层已经用了 Nginx 做反向代理那你只需把 80/443 放给 Nginx由 Nginx 决定转发到哪个后端。这种情况下再叠加 firewalld 的forward-port反而会造成多一层跳转、多一次带宽损耗还让故障定位变麻烦。我的经验是三层分流“网络层能解决的如按 IP 限制交给 firewalld应用层能解决的如路径分发、超时控制交给 Nginx需要改变端口或 IP 的场景才用端口转发。” 遵循这个原则你的防火墙规则和 Web 配置都会清爽很多。5. 配置持久化、备份迁移把防火墙规则当成代码来管理5.1 推荐的“临时→验证→固化”三步法生产环境最忌讳一上来就写--permanent因为一旦规则写错重载后你可能直接把自己关在服务器外面。正确姿势是# 第一步临时放通 firewall-cmd --add-port8080/tcp # 第二步验证业务正常 curl http://127.0.0.1:8080/health # 第三步固化 firewall-cmd --runtime-to-permanent--runtime-to-permanent会把当前运行时配置全部写入永久配置文件。使用前建议先执行firewall-cmd --list-all检查一遍确认没有临时调试用的垃圾规则再固化。5.2 备份与迁移防止服务器重建后规则丢失每次大改规则之前我都习惯把配置目录打包备份mkdir -p /backup/firewalld cp -r /etc/firewalld /backup/firewalld/$(date %F)迁移到新机器时可以直接把整个/etc/firewalld目录拷过去然后重载systemctl restart firewalld注意/etc/firewalld里保存的是用户自定义配置系统默认配置在/usr/lib/firewalld两边不要混淆。自己手动改过/etc/firewalld/zones/public.xml的话迁移时重点盯这个目录。5.3 用命令行工具批量处理规则的实用技巧大量重复规则比如放行 1000 个端口不要一条条手敲可以直接写一个循环脚本for port in $(seq 8000 9000); do firewall-cmd --permanent --add-port${port}/tcp done firewall-cmd --reload但我不建议真的放行 1000 个端口除非业务确实需要。更合理的做法是把业务拆分成服务文件/etc/firewalld/services/myapp.xml然后通过--add-servicemyapp一键放行一组端口后续维护只需要改这个 XML 文件。服务文件示例?xml version1.0 encodingutf-8? service shortMyApp/short descriptionMy application ports/description port protocoltcp port8080/ port protocoltcp port8443/ /service放到/etc/firewalld/services/后执行firewall-cmd --permanent --add-servicemyapp firewall-cmd --reload这种方式比散落一堆--add-port规则要清晰得多审计时也是看文件比翻命令历史舒服。5.4 使用 firewall-config 图形工具与命令行的分工如果服务器带了图形界面firewall-config可以让你用鼠标完成大部分配置。它有两个 Tab运行时和永久切换时界面会显著变灰提示你。但我的建议是生产服务器尽量用命令行因为脚本化、可审计、可复现图形工具更适合学习阶段理解 zone 和策略之间的关系。用图形工具改完实际生效的还是那套底层 XML所以不会和命令行冲突。6. 常见问题与排查技巧实录别再被“规则不生效”折磨了6.1 规则不生效的五层排查法当服务无法访问时不要只看 firewalld。我通常按下面这个顺序排查层级命令/工具检查内容应用层ss -lntp确认端口是否真的在监听firewalld 层firewall-cmd --list-all确认规则是否已加载nftables 层nft list ruleset确认底层规则链是否匹配预期路由层ip route、ping确认回程路由是否正常物理层ping、telnet确认链路和防火墙设备未拦截很多“firewalld 配置了却没用”的案例最后都发现是服务根本没启动、监听端口不对、或者策略落在了错误的 zone。这五层逐层往下查基本能定位 99% 的问题。6.2 排查 zone 分配问题的两个核心命令firewall-cmd --get-active-zones ip addr show前者告诉你网卡当前属于哪个 zone后者告诉你网卡 IP 是否与你设想的一致。有一次我在publiczone 里放行了端口但业务流量从ens192出去而ens192被分配到了internalzone自然不生效。改完网卡绑定后问题立刻解决。另外要警惕“默认 zone”和“接口绑定 zone”不一致的情况。--get-default-zone返回的是新接口进入时的默认区域但如果接口被显式绑定到某个 zone后者的优先级更高。访问某个端口前先想明白它从哪个接口进来再决定检查哪个 zone。6.3 重载规则导致已有连接断掉怎么办firewall-cmd --reload会重新加载所有规则这可能导致已经建立的连接被中断。对于数据库这类长连接服务影响会比较明显。解决办法是使用--reload以外的另一种方式如果只是修改服务或端口firewalld 通常会尽力维持已有连接状态但如果有富规则变了连接还是会被切断。更稳妥的做法是使用--complete-reload之外的方案不要随便用--complete-reload它会彻底清空所有状态。生产环境里宁可用--reload然后重新建连也不要为了“彻底”而把正在运行的业务全踢下线。真的遇到了连接中断最快的恢复方式就是让客户端重连。但对于无法接受断连的关键进程建议把规则变更安排在业务低峰期并且先备份旧规则。6.4 富规则“先拒绝后允许”的陷阱富规则的求值是按写入顺序的但很多人以为是“最后一条生效”实际是“按列表从上到下的顺序依次匹配”。如果你先写了一条drop的富规则再写一条accept的富规则那么后写的accept不会拯救先前被drop的流量因为第一条已经命中并结束了流程。要避免这个问题把更精确的accept规则放在前面把兜底的drop规则放在后面。6.5 常用工具确认规则是否真的生效nft list ruleset能直接看到内核态规则这条命令查出来如果与你期望的不一致那就是 firewalld 没有正确加载。这时候先执行firewall-cmd --reload systemctl status firewalld如果还是不生效再检查/etc/firewalld/firewalld.conf里的FirewallBackend配置。有些系统装的 firewalld 版本较老或者手工动过 iptables 服务会与 firewalld 冲突。此时不要双轨混跑统一用 firewalld 管理把iptables和ip6tables服务设为 disabled。6.6 从网络设备到 Linux 主机锐捷、ensp 与 firewalld 的联动思考最近和培训机构的一位朋友聊起很多学网络的人在用ensp做华为路由器/防火墙的实验比如配置 Web 登录、配置安全策略。这类硬件防火墙的配置思路和 firewalld 有相通之处都有“区域/安全域”的概念都强调策略放行的最小化都需要考虑 NAT、路由和会话状态。但两者也有明显差异华为 USG 防火墙的策略是配置在接口/安全域上的firewalld 的 zone 则更偏主机内部软件定义。实际企业交付中网络设备锐捷、华为等负责边界防护和 NAT 映射Linux 服务器上的 firewalld 负责主机层防护两者是互补关系。在模拟器环境里做完防火墙策略实验后建议把同样的“源 IP 限制、目标端口限制、最终动作”在 firewalld 上复现一遍。你会更深刻地体会到策略的本质是“谁在什么条件下可以访问什么”无论底层是硬件芯片还是 netfilter 框架思路完全一致。6.7 通过日志观察被拦流量排查被拦截的流量日志是重要依据。firewalld 的 drop 动作默认不一定打日志需要显式在富规则里加log。日常运维我会对可疑 IP 加一条带日志的 drop 规则firewall-cmd --permanent --add-rich-rulerule familyipv4 source address203.0.113.0/24 log prefixDROP_SCAN: levelinfo drop然后实时观察journalctl -f | grep DROP_SCAN根据日志前缀快速确认是不是自己的规则拦的还是服务本身异常这能省下大量排查时间。7. 实操过程复盘与后续建议在这个环节我把自己最近一次线上防火墙调整的完整过程复述一遍。某台 Nginx 反向代理服务器业务要求办公网段可以访问 80/443 和 22 端口其他来源只能访问 443另外要把两内网服务的端口映射到这台公网服务器上来。我的执行记录如下# 1. 查看现有配置 firewall-cmd --list-all # 2. 设置默认 zone 为 drop拒绝一切未明确放行的流量 firewall-cmd --set-default-zonedrop # 3. 放行办公网段 SSH firewall-cmd --permanent --zonedrop --add-rich-rulerule familyipv4 source address192.168.20.0/24 service namessh accept # 4. 放行所有来源的 443 firewall-cmd --permanent --zonedrop --add-servicehttps # 5. 放行办公网段 80内部访问可能走 HTTP firewall-cmd --permanent --zonedrop --add-rich-rulerule familyipv4 source address192.168.20.0/24 service namehttp accept # 6. 配置端口转发 firewall-cmd --permanent --zonedrop --add-forward-portport8443:prototcp:toport443:toaddr10.10.1.88 firewall-cmd --permanent --zonedrop --add-forward-portport2222:prototcp:toport22:toaddr10.10.1.99 # 7. 开启内核转发 sysctl -w net.ipv4.ip_forward1 echo net.ipv4.ip_forward 1 /etc/sysctl.conf # 8. 开启伪装 firewall-cmd --permanent --zonedrop --add-masquerade # 9. 重载并验证 firewall-cmd --reload firewall-cmd --list-all这套配置的思路是“默认全拒、按需放行”对公网服务尤其合适。因为默认 zone 设置为 drop所有未匹配流量都会被丢弃攻击面被压缩到最小。这里需要注意--set-default-zonedrop只影响“新的接口/连接”会被分配到 drop zone但已经有网络连接或已经绑定 zone 的接口不会自动切换必须逐个接口重新--change-interface或重启。这是我在验证时踩的小坑特意标注出来。这个过程中我犯过的一个错误是忘记开启ip_forward导致端口转发的数据包到了内核就丢了。排查时用tcpdump -i any port 8443能抓到入方向的包但完全没有发出到内网顺着链路往下排查才找到根因。做这类改动时强烈建议你保留一个“逃生窗口”开一个临时放行的富裕 IP 来源规则比如办公网段 full access 或至少保留 22 端口避免规则一重载就把自己锁在门外。如果真的运气不好把自己锁在外面可以联系机房或带外管理通过控制台登录把 firewalld 停掉或恢复默认配置。8. 最后分享两个实用习惯firewalld 用到现在我觉得真正提升效率的不是某个命令而是两个习惯。第一个习惯是“配置即代码”。我会把防火墙规则按服务器角色整理成单独的 shell 文件比如web-firewall.sh、db-firewall.sh放在/root/scripts/下每次改动后更新脚本再手动执行或走自动化平台下发。这样无论是审计还是新机器初始化都能快速复现同一套规则避免凭记忆敲命令造成两台机器规则不一致。第二个习惯是“变更前留快照变更后留验证”。快照不止是cp -r /etc/firewalld还要负责记录当时的--list-all输出。变更后我会把两条命令的 diff 拿出来看一遍核对“预期变更”和“实际变更”是否一致。这个做法看起来很笨但在多人维护的环境中真的能减少大量来回扯皮。如果你正在学习华为设备的防火墙配置或者刚从网络模拟器环境切到真实 Linux 服务器运维我的建议是先花一个下午把 firewalld 的六个 zone 用意和一个 zone 的配置完整过一遍再回到模拟器里对比一下你会发现从网络设备到主机防火墙的抽象层次虽然不同但安全策略的灵魂完全一样。
返回列表