1. Linux 服务器安全防线:为什么 iptables 和 SELinux 必须一起讲
做运维这些年,有个场景我遇到过太多次:服务器上线前做安全自查,发现 22 端口暴露在公网,防火墙规则裸奔,SELinux 直接被 setenforce 0 关掉,然后所有人都觉得“没事了”。等真正被扫描爆破或者被上传了恶意脚本,才回头来找问题根源。
Linux 服务器安全配置这件事,我个人的观点很明确:iptables 和 SELinux 是两条腿,缺一条都会瘸。iptables 管的是网络层的“门禁”,决定谁的数据包能进来、往哪走;SELinux 管的是系统内部的“权限边界”,决定一个进程拿到网络请求之后能不能读某个文件、连某个端口、执行某个操作。前者是能从外面挡住绝大部分攻击,后者是万一被突破,能把横向扩散的损失压到最低。两个配合起来,才算一套完整的防御体系。
这篇内容我准备了很久,把实际运维中踩过的坑、现场排障的日志、以及最终落地的配置方案都整理出来了。不管是刚接手 Linux 服务器的新人,还是想把自己的安全基线补全的老手,这篇都能给你一套可以直接抄作业的思路。我会先从 iptables 的四表五链讲清楚规则是怎么流转的,再深入 SELinux 的三大模式和类型强制机制,最后给出我实际生产环境里在用的联合配置方案和排障记录。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. iptables 实战内核:规则匹配、链表流转与关键参数详解
2.1 netfilter 框架下,iptables 到底在处理什么
要弄懂 iptables,先得知道它背后是 netfilter。netfilter 是 Linux 内核里的一组钩子(hook),数据包每经过一个关键节点,内核就会停下来问问:有没有规则要处理?iptables 只是用户态的工具,真正干活的是内核态的 netfilter 框架。
打个比方,数据包在网络协议栈里流动,就像一个人进一栋大楼。大楼门口有一个保安查证件(PREROUTING),前台会指导你去哪个部门(FORWARD),办完事出门还有保安看一眼(POSTROUTING)。而 INPUT 和 OUTPUT 这两个链,则是“这个人要进入某个房间”和“这个人从房间出来”时的那道检查。
数据包从网卡进来后,首先经过 PREROUTING 链,这时候可以做 DNAT、重定向之类的操作。然后内核会做一次路由判断:如果目的地是本机,数据包就走 INPUT 链,交给本地进程处理;如果目的地是别的机器,就走 FORWARD 链转发出去。从本机发出的数据包,先过 OUTPUT 链,最后统一经过 POSTROUTING 链做 SNAT 或 masquerade。
理解这个流程,比死记命令重要得多。很多新手写规则时搞不清“为什么我做了 -A INPUT 限制,内网还是能访问”,原因往往是数据包走的根本不是 INPUT 链,而是 FORWARD 链。比如你在这台机器上用 Docker 起了一个映射端口的容器,数据包到宿主机后要转到容器网段,走的是 FORWARD,只在 INPUT 上写规则当然没效果。
2.2 四表五链的职责边界:filter、nat、mangle、raw 怎么选
iptables 里最容易被混淆的就是“表”和“链”的对应关系。虽然叫“四表五链”,但不是每个表都有完整的五条链。我做了个表,方便你对照着看:
| 表 | 内置链 | 主要功能 | 典型场景 |
|---|---|---|---|
| filter | INPUT、FORWARD、OUTPUT | 数据包过滤,允许或拒绝 | 开放端口、限制来源 IP |
| nat | PREROUTING、INPUT、OUTPUT、POSTROUTING | 地址转换,修改源或目的地址 | 端口映射、内网上网共享 |
| mangle | 全部五条链 | 修改数据包标记、TTL、TOS 等 | 策略路由、QoS 流量整形 |
| raw | PREROUTING、OUTPUT | 设置 NOTRACK,跳过连接跟踪 | 高流量场景下降低 conntrack 负载 |
我在实际配置里,绝大多数时间只碰 filter 和 nat 两张表。mangle 你可能会在特殊场景下用到,比如给某些包打 mark 然后配合策略路由,但日常防御策略用不上。raw 表我提一句:如果某个网卡流量极大,conntrack 表被撑爆导致丢包,可以把这些流量在 raw 表里设为 NOTRACK,跳过连接跟踪。这是性能调优手段,不是常规安全配置。
选表时有个简单的判断方法:你想“拦”还是“转”。“拦”用 filter,“转”用 nat。想改数据包头部的字段,才考虑 mangle。想跳过状态跟踪,才动 raw。用错表的后果往往是规则不生效,看起来写了等于没写。
2.3 常用规则写法与参数逐一拆解
这里我列一些实际操作中最常用的 iptables 命令,配合注释说明每个参数的含义。你执行的时候,建议先在测试环境验证,再上生产。
bash复制# 查看当前 filter 表所有规则,带行号方便后续删除
iptables -L INPUT -n --line-numbers
# 允许本机回环接口,这个一定要放前面,否则部分本机通信会被阻断
iptables -A INPUT -i lo -j ACCEPT
# 允许已建立的连接及相关联的连接通过
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 放行指定来源 IP 访问 SSH 端口,其他来源一律拒绝
iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP
# 限制单个 IP 每分钟最多新建 10 个到 80 端口的连接,超过则丢弃
iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW -m limit --limit 10/minute --limit-burst 10 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j DROP
注意第一个命令里的 -n 参数,它让 iptables 不做反向域名解析。如果服务器 DNS 有问题,不加 -n 会导致命令卡住几十秒,这是新手最容易遇到的现象。
--ctstate ESTABLISHED,RELATED 这条规则要养成习惯放在 INPUT 链最前面。它表示:如果这个连接之前已经通过检查,后续返回的数据包直接放行,不需要再重新匹配规则。如果你把这条放在规则最后,会出现一种情况:SSH 登录成功后,每次敲命令回显的数据包还要从头匹配一遍规则,规则一多延迟就很明显,甚至可能因为某条 DROP 规则把回来的包也杀了,导致“能连上但敲命令没反应”。
limit 模块是个好东西,但别指望它做精确的限速。它是基于令牌桶的“速率限制”,允许短时间的突发流量超过平均值,适合用来挡住粗暴的端口扫描和密码爆破,不适合做带宽控制。真要做带宽限制,需要借助 tc。
2.4 保存规则与开机自启:一条命令搞定,别让配置白写
很多人配置完 iptables 后发现一个问题:重启服务器,规则全没了。这是因为 iptables 的规则是运行时内存里的,如果不导出保存,系统一重启就回到初始状态。
在 CentOS/RHEL 系上:
bash复制# 存到 /etc/sysconfig/iptables
iptables-save > /etc/sysconfig/iptables
# 或者用 service 提供的封装
service iptables save
在 Debian/Ubuntu 系上,需要先安装 iptables-persistent:
bash复制apt install -y iptables-persistent
netfilter-persistent save
netfilter-persistent reload
我踩过的坑是:用 iptables-save > /etc/sysconfig/iptables 这种方式,如果系统里同时装了 firewalld,重启后 firewalld 可能会覆盖你的 iptables 规则。所以生产环境建议二选一,不要混用。我个人更倾向于用 firewalld 的富规则来做,但如果你的场景是纯命令行管理的旧系统,iptables 依然是确定性最高、最不容易被“自动配置”干扰的选择。
保存规则前,务必确认当前加载的规则是你真正想要的最终版本。一个常规检查动作是:iptables-save | grep -E "DROP|REJECT",先数一数有多少条拒绝规则,心里有个底。还有一点:iptables-save 会输出包含默认策略的信息,比如 :INPUT DROP,如果你没设默认策略,这里显示的是 ACCEPT,也正常。
3. SELinux 深度解析:类型强制、策略模块与常见排障现场
3.1 SELinux 三大模式:Enforcing、Permissive、Disabled 到底差在哪
SELinux 不是防火墙,它更像是一套“内核级的权限审查系统”。传统 Linux 权限靠的是用户、组、其他(DAC,自主访问控制),你只要有文件权限,就能读能写。SELinux 在此基础上加了一层强制访问控制(MAC):就算 root 用户也要受到策略约束。进程能访问什么资源,不是看它属于哪个用户,而是看它的安全上下文标签(security context)和策略规则是否匹配。
SELinux 有三种模式,我分别说一下适用场景:
| 模式 | getenforce 输出 | 行为 | 适用场景 |
|---|---|---|---|
| Enforcing | Enforcing | 违反策略的操作被直接阻止,并写入 audit 日志 | 生产环境推荐 |
| Permissive | Permissive | 违反策略的操作会被记录,但不阻止 | 排查策略问题、灰度开启时临时用 |
| Disabled | Disabled | SELinux 完全关闭,不使用任何策略 | 仅建议在明确不需要时关闭 |
切换模式的命令是 setenforce 0(Permissive)和 setenforce 1(Enforcing),但这个命令重启后会失效。想要永久指定模式,改 /etc/selinux/config 里的 SELINUX=enforcing。这里有个重要的坑:如果你一开始是 Disabled 状态,直接改成 Enforcing 重启,系统可能会因为文件标签没有正确初始化而出现各种服务起不来的问题。从 Disabled 切换之前,最好先手动执行 touch /.autorelabel,让系统重启时重新标记所有文件。
我见过不少团队的做法是“SELinux 太烦了,直接关掉”,这在安全要求严格的业务场景里其实是给自己埋雷。SELinux 挡住的服务异常,用下面要说的排障方法,大多数十分钟内就能解决,没必要因噎废食。
3.2 类型强制(Type Enforcement)机制:主体、客体与安全上下文
SELinux 里最核心的概念是“类型强制”。每个进程(主体)和每个文件/端口(客体)都有一个类型标签,比如 httpd 进程的类型是 httpd_t,网页文件通常是 httpd_sys_content_t,SSH 服务是 sshd_t。策略规则规定了某类主体能访问哪些类型的客体。
用一个简单例子说明:你启动了 Nginx,Nginx 进程的类型是 httpd_t。它想读取 /var/www/html/index.html,这个文件被打上了 httpd_sys_content_t 标签。策略里有一条规则说 httpd_t 可以读 httpd_sys_content_t,于是访问被允许。但如果你把文件放到了 /home/user/www/index.html,而这个文件的多类型没有设置好,标签可能是 user_home_t,Nginx 就会报 Permission denied。即使你是 root 也照样被拒,这就是 MAC 和 DAC 的区别。
查看一个文件的 SELinux 上下文:
bash复制ls -Z /var/www/html/index.html
修改文件上下文的标准做法不是直接 chcon,而是用 semanage 定义规则,再用 restorecon 应用:
bash复制# 定义 /data/web 目录及其子目录的默认上下文类型
semanage fcontext -a -t httpd_sys_content_t "/data/web(/.*)?"
# 应用规则
restorecon -Rv /data/web
注意 (/.*)? 这个正则写法,少了它,只有 /data/web 目录本身会被标记,里面新建的文件不会继承类型。我见过好几个同事在这里栽过跟头,文件放进去之后服务还是 403。
3.3 布尔值(Boolean)与端口标签:最常用的两类调整
SELinux 的布尔值可以理解成“策略里的开关”。某些功能默认是关闭的,你需要打开对应的布尔值才能让服务正常工作。举几个实际案例:
bash复制# 查看所有 httpd 相关的布尔值及其当前状态
getsebool -a | grep httpd
# 允许 httpd 发起网络连接(比如 Nginx 反代后端接口)
setsebool -P httpd_can_network_connect on
# 允许 httpd 连接数据库(MySQL 默认端口 3306)
setsebool -P httpd_can_network_connect_db on
# 允许 httpd 发送邮件
setsebool -P httpd_can_sendmail on
-P 参数表示持久化,重启后依然生效。如果不加 -P,只对当前运行环境有效。
端口标签是另一个容易踩坑的点。默认情况下,SELinux 只允许 httpd 监听 80、443 等标准端口。如果你把 Nginx 改成了监听 8080,就会看到类似 Permission denied 的报错,而实际上端口没被占用、进程也有权限。原因就是 SELinux 不允许 httpd_t 类型绑定 8080 端口。
解决方案:
bash复制# 查看当前 httpd 允许监听的端口
semanage port -l | grep http
# 把 8080 加入 httpd 允许监听的端口列表
semanage port -a -t http_port_t -p tcp 8080
这里补充一句:semanage 命令属于 policycoreutils-python-utils 包,有些最小化系统没装。报 command not found 时先装包:CentOS 用 yum install -y policycoreutils-python-utils,Ubuntu 用 apt install -y policycoreutils-python-utils selinux-utils。
3.4 SELinux 排障三板斧:audit.log、audit2why、audit2allow
SELinux 排障的核心依据是 /var/log/audit/audit.log。服务一旦被策略拦截,这条日志里会出现 avc: denied 的记录。你不需要手动去 grep 大海捞针,直接用工具分析就行。
我的标准流程是三步:
第一步,确认服务异常确实由 SELinux 引起。先临时切到 Permissive 模式,重启服务测试,如果恢复正常,基本可以确定是 SELinux 策略的问题。注意不要太久停留在 Permissive,测试完要恢复。
第二步,调用 audit2why 看拦截原因:
bash复制# 查看最近被拦截的原因
audit2why < /var/log/audit/audit.log | head -50
第三步,如果是需要永久放行的场景,用 audit2allow 生成并加载策略模块:
bash复制grep "httpd_t" /var/log/audit/audit.log | audit2allow -M my_httpd_module
semodule -i my_httpd_module.pp
这里提醒一句:audit2allow 是“按日志生成放行规则”的工具,使用前一定要确认日志里拦截的操作是正当业务行为。如果你是在被入侵之后跑这个命令,等于给攻击行为发了一张合法通行证。生产环境用这个工具前,最好把日志里对应的源 IP、时间点核对一遍。
还有一个常见误区:很多人修改了 SELinux 配置后,用 systemctl restart httpd 看服务起来了就认为改好了。实际上有些策略变更需要重新标记文件系统或者重新加载模块,最好养成修改完策略后执行 systemctl daemon-reload 再重启服务的习惯。
4. 从零到一:iptables 和 SELinux 的联合防御配置实战
4.1 防御体系的整体设计思路:门禁加内控,缺一不可
我倾向于把 Linux 服务器的安全防御分成两层:网络层门禁由 iptables 负责,系统内控由 SELinux 负责。iptables 的目标是最大化缩小暴露面,SELinux 的目标是最小化单点失陷后的破坏半径。
设计时的几个原则,我觉得值得先列出来:
- 默认拒绝。iptables 的默认策略设置为 DROP,然后逐条放行必要的端口和来源。不要反过来先 ACCEPT 再写拒绝,那样你漏写的端口就全裸奔了。
- 最小权限。SELinux 的布尔值能不开就不开,比如
httpd_can_network_connect这个开关,如果你只是静态服务,完全不用打开。真需要反代时才开,而且最好限定到具体进程。 - 规则有序。iptables 是按顺序匹配的,命中即停止。所以放行规则在前,拒绝规则在后;状态放行在最前。
- 可回滚。所有配置都写成脚本,改之前备份,改之后能一键恢复。
4.2 场景一:Nginx 网页服务的完整加固过程
假设有一台 CentOS 服务器,跑着 Nginx,监听 80 和 443,SSH 用 22 端口,来源是办公网段 203.0.113.0/24,其他一概不允许访问。
第一步,设置默认策略:
bash复制iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
第二步,配置白名单和状态放行:
bash复制iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -s 203.0.113.0/24 -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
第三步,防止 SYN Flood(经验参数,量级可根据业务调整):
bash复制iptables -A INPUT -p tcp --syn -m limit --limit 20/second --limit-burst 50 -j ACCEPT
第四步,SELinux 侧配置:
- 确认 Nginx 监听在标准端口,如果是 8080 就按上文 semanage port 加上。
- 网页根目录用
/var/www/html默认标签,或者按上文用 semanage fcontext 自定义目录。 - 检查相关布尔值,只需要最基本的,不要一股脑全开。
第五步,验证并保存:
bash复制iptables-save > /etc/sysconfig/iptables
curl -I http://127.0.0.1
这里有个细节:做完默认 DROP 后,如果你忘记加 -i lo 放行,本地 curl 测试就会卡住。因为 curl 访问 127.0.0.1 的数据包走的是 lo 接口,被 DROP 掉了,表现是“服务明明起来了,但本机无法访问”。这是新手最经常碰到的现象,先检查 lo 放行规则。
4.3 场景二:MySQL 数据库只允许内网访问,外部一律拒绝
数据库服务器通常不需要对公网开放端口。配置上分三层来处理。
iptables 层,只允许应用服务器网段访问 3306:
bash复制iptables -A INPUT -s 10.0.0.0/24 -p tcp --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp --dport 3306 -j DROP
MySQL 配置层,确保监听地址只在内网网卡上:
ini复制bind-address = 10.0.0.10
SELinux 层,有些发行版对 MySQL 使用 mysqld_port_t 类型。如果你的 MySQL 跑了非标准端口,需要:
bash复制semanage port -a -t mysqld_port_t -p tcp 3307
这三层任何一层出问题,外部都无法访问。反过来讲,这也意味着你排查问题时得逐层检查:先看 MySQL 监听地址,再看 iptables 规则,最后确认 SELinux 是否拦截。我用一个“从外到内”的排查命令序列:
bash复制# 第一层:宿主机上能否访问
telnet 10.0.0.10 3306
# 第二层:iptables 是否有拦截记录
iptables -L INPUT -n -v | grep 3306
# 第三层:SELinux 审计日志里有没有 mysqld 相关拒绝
grep mysqld /var/log/audit/audit.log | grep avc
4.4 自动化配置脚本与一键回滚
生产环境手动敲规则容易漏,我习惯把整个加固过程写成脚本,放到运维仓库里统一管理。脚本结构大概是:先备份当前规则,再加载新规则,最后执行验证。
bash复制#!/bin/bash
# 备份当前 iptables 规则
mkdir -p /backup/iptables/$(date +%F)
iptables-save > /backup/iptables/$(date +%F)/iptables.rules
# 加载新的安全策略脚本
/path/to/security/apply_iptables_rules.sh
# 验证 SSH 是否正常(如果 SSH 断了,说明规则有问题)
timeout 5 bash -c 'echo > /dev/tcp/127.0.0.1/22' 2>/dev/null && echo "SSH OK"
# SELinux 模块备份
semodule -l > /backup/selinux/modules_$(date +%F).list
回滚时直接:
bash复制iptables-restore < /backup/iptables/2025-01-01/iptables.rules
需要提醒的是:回滚脚本和设备要放在服务器本地。如果存放在某个依赖这台服务器才能访问的远程系统里,真出问题时可能“先有鸡还是先有蛋”。另外,每次改动安全策略前给 audit.log 做个轮转标记,比如先 service auditd rotate,这样接下来产生的日志就是新策略的单独记录,排查起来干净很多。
5. 实战排障与经验避坑:高频问题与解决思路
5.1 iptables 常见问题速查
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| 规则配置后不生效 | 表选错了,或规则顺序不对 | iptables -L -n -v 查看命中计数,确认数据包走的是哪条链 |
| 重启后规则消失 | 没有持久化保存 | iptables-save > /etc/sysconfig/iptables,并确认系统启动时会加载 |
| 本机访问服务卡住 | 没放行 lo 回环接口 | 加上 -A INPUT -i lo -j ACCEPT |
| FTP 模式无法上传 | 主动/被动模式的数据连接被拦 | 加载 nf_conntrack_ftp 模块,放行 RELATED 状态 |
| Docker 映射端口外网不通 | FORWARD 链被默认 DROP | 放行 docker0 网桥流量,或在 DOCKER 链里加规则 |
| conntrack 表满导致丢包 | 连接跟踪数量不够 | 调大 net.netfilter.nf_conntrack_max,或对高流量端口设置 NOTRACK |
conntrack 表满这个问题,我多说一句。dmesg 里如果出现 nf_conntrack: table full, dropping packet,说明服务器连接数超过了默认上限。简单粗暴的办法是调大参数:
bash复制sysctl -w net.netfilter.nf_conntrack_max=1048576
echo "net.netfilter.nf_conntrack_max=1048576" >> /etc/sysctl.conf
但根本解决方案是减少不必要的连接跟踪。对于某些纯转发的高流量端口,可以在 raw 表设置:
bash复制iptables -t raw -A PREROUTING -p tcp --dport 80 -j NOTRACK
注意,NOTRACK 之后,这条连接就不会有 ESTABLISHED 状态了,如果你的 filter 规则依赖 conntrack 状态放行,需要另外显式放行返回流量。
5.2 SELinux 常见问题速查
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| 服务启动报 Permission denied,但权限和属主都对 | 安全上下文类型不匹配 | ls -Z 查看标签,semanage fcontext + restorecon 修正 |
| 自定义目录里的 Web 文件访问 403 | 目录没有正确的 httpd_sys_content_t | 按上文方式定义 fcontext 规则 |
| 改完配置重启后还是报错 | 布尔值没加 -P 或未重新加载模块 |
重新执行带 -P 的命令,修改后重启服务测试 |
| 日志里频繁出现 avc denied,但业务正常 | 存在一些尝试性访问被拦 | 分析日志确认来源,若为本业务合理行为,用 audit2allow 放行 |
| 从 Disabled 切到 Enforcing 后系统异常 | 文件标签没有重新初始化 | 执行 touch /.autorelabel 后重启 |
| 关闭 SELinux 后服务正常,但想重新开启 | 应用的文件标签不完整 | 重新标记文件系统并逐模块验证 |
我特别想强调一下“SELinux 只是放行还不够”这件事。有些时候,你明明用 audit2allow 生成了策略,服务依然报错。这种情况多半是因为策略模块的 allow 规则不全面,或者某个布尔值还需要同时调整。比如 Nginx 需要跟 PHP-FPM 通信,光靠打开 httpd_can_network_connect 不够,还要确认 PHP-FPM 的 socket 文件类型是 httpd_var_run_t 之类能被 httpd_t 访问的类型。一步步用 ausearch -m avc -ts recent 跟踪最新拦截日志,是最稳妥的办法。
5.3 日常巡检清单:安全配置不是配完就完
安全策略是动态的,不是配完就一劳永逸。我每次值班交接会检查下面这些点,你可以直接拿走当模板:
- iptables 规则是否和预期一致:
iptables-save | diff - <(cat /etc/sysconfig/iptables) - 有没有新增的监听端口:
ss -lntp | grep -v "127.0.0.1"对比业务白名单 - SELinux 是否还在 enforcing:
getenforce - 最近一小时有没有新的 avc denied:
ausearch -m avc -ts recent - conntrack 当前使用率:
sysctl net.netfilter.nf_conntrack_count对比nf_conntrack_max - 关键服务的布尔值有没有被改动:
getsebool -a | grep -E "httpd|ssh"
这些检查不适合全靠肉眼。建议写成一个巡检脚本放到 crontab 里,有异常就告警到 IM 工具。我个人更推荐把 diff 的退出码作为判断条件:非 0 就说明配置有变动,立刻通知值班人员。
6. 写在最后:一些踩过坑后的真实体会
安全配置领域有个很普遍的现象:攻防演练时大家才想起来补课,平时总觉得“服务器没被入侵就是安全”。但真正的安全是层层设防,iptables 挡掉一批扫描和爆破,SELinux 拦住一批因为服务配置不当或者代码漏洞导致的越权操作,这两层都无法单独覆盖所有场景。我在实际加固过上百台服务器之后,最大的体会是:宁可配置繁琐一点,也不要因为“省事”把 SELinux 关掉,把防火墙规则清空。那些“关掉之后一切正常”的舒适感,往往只是把风险延后了,并没有消除。
如果你是从零开始给自己的服务器做安全基线,我建议按这个顺序来:先梳理业务端口清单,然后落 iptables 默认拒绝策略,再逐服务验证连通性,最后开启 SELinux enforcing 模式,跑一遍业务回归测试。过程中有任何一步异常,都不要跳过,用 audit 日志和 conntrack 状态找到根因再继续。等这套流程跑顺了,你会发现自己对 Linux 服务的理解也会深一层——因为安全加固本身就是一次对系统运行机制的全面体检。
