CentOS 7.9启用SELinux后,主备服务器如何同步策略并降低切换风险?
先不要把“启用 SELinux 后切换失败”直接归因于 SELinux 本身。主备服务器真正容易出现的问题,是两台机器的策略版本、semanage 本地配置、策略模块、文件安全上下文或服务端口定义不一致。只要备用机在平时没有按主机状态持续校准,切换时就可能出现服务无法启动、数据目录不可读、监听端口被拒绝等现象。
第一步应先判断主备是否具备“同一套策略、同一套路径、同一套服务角色”的前提。如果系统版本、应用目录和端口都一致,可以采用“相同策略包 + semanage 导出导入 + 自定义模块同步 + 数据标签校验”的方式;如果备用机的目录、服务角色或挂载点不同,则不能直接复制主机配置,而应分别维护对应路径的文件上下文和端口规则。排查顺序应从网络和服务状态开始,再进入 SELinux 策略、文件标签和审计日志,避免在服务根本没有启动时误改策略。
先确认主备是否属于同一策略边界
在两台服务器上分别执行基础检查,先记录结果,不要急于修改配置:
cat /etc/centos-release
uname -r
sestatus
getenforce
rpm -q selinux-policy selinux-policy-targeted policycoreutils policycoreutils-python
重点关注以下条件:
| 检查项 | 可以直接同步的情况 | 需要单独处理的情况 |
|---|---|---|
| CentOS 版本 | 两台均为 CentOS 7.9 | 小版本、策略包或关键软件版本不同 |
| SELinux 类型 | 均为 targeted | 一台为其他策略类型,或一台处于 disabled |
| 应用路径 | 主备使用相同绝对路径 | 主备挂载点、目录结构不同 |
| 服务端口 | 服务监听端口和协议一致 | 备用机端口发生变化 |
| 自定义策略 | 有可追溯的 .pp 模块文件或构建产物 | 只在主机上临时生成,找不到来源 |
| 数据标签 | 复制机制保留 security.selinux 扩展属性 | 数据复制后标签丢失或由不同策略生成 |
如果主备的应用目录都是 /srv/app,服务端口都是 TCP 8080,且策略类型和策略包版本一致,那么直接同步本地策略配置通常风险较低。如果主机使用 /data/app、备用机使用 /srv/app,则不能只导入主机的文件上下文规则,必须重新定义备用机实际路径对应的上下文。
先做基线和可回滚备份
启用或切换 SELinux 前,应确保能够通过控制台、带外管理或其他独立管理入口登录备用机。否则一旦策略阻断远程登录,网络服务和远程运维可能同时失效。
建议在主机和备用机上分别建立备份目录:
BACKUP="/root/selinux-backup-$(date +%F-%H%M%S)"
install -d -m 0700 "$BACKUP"
cp -a /etc/selinux/config "$BACKUP/"
sestatus > "$BACKUP/sestatus.txt"
getenforce > "$BACKUP/getenforce.txt"
semodule -lfull > "$BACKUP/semodule-full.txt"
getsebool -a | sort > "$BACKUP/getsebool.txt"
semanage export -f "$BACKUP/semanage.export"
sha256sum "$BACKUP"/* > "$BACKUP/SHA256SUMS"
如果提示找不到 semanage,先确认 policycoreutils-python 是否安装:
rpm -q policycoreutils-python
command -v semanage
CentOS 7 中,semanage 通常由 policycoreutils-python 提供。安装缺失软件包前,应确认软件源、维护窗口和本地软件包版本,避免在主备切换前临时引入不同版本的策略工具。
备份的作用不是让两台服务器直接覆盖整个 /etc/selinux 目录,而是保存可审计、可比较、可回滚的策略输入。尤其不要把主机的 /etc/selinux/targeted 目录直接使用 cp 或 rsync 覆盖到备用机,这可能混合不同版本的策略数据库和运行时文件。
同步策略包和 semanage 本地配置
SELinux 的基础策略由软件包提供,主备服务器应尽量保持相同版本。可以分别记录包版本:
rpm -q --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' \
selinux-policy selinux-policy-targeted policycoreutils policycoreutils-python
如果结果不一致,优先统一备用机的软件包版本,再导入本地配置。只复制导出文件而不统一策略包,可能导致某些类型、布尔值或规则在备用机上不存在。
主机上的本地策略配置可通过 semanage export 导出:
semanage export -f /root/selinux-backup/current/semanage.export
sha256sum /root/selinux-backup/current/semanage.export
将文件通过受控方式传到备用机后,先保存备用机当前配置:
mkdir -p /root/selinux-backup/before-import
semanage export -f /root/selinux-backup/before-import/semanage.export
确认文件校验值一致,再在维护窗口内导入:
semanage import -f /root/selinux-backup/current/semanage.export
semanage export 通常可以覆盖以下本地定制内容:
- 持久化布尔值;
- 文件上下文规则;
- SELinux 端口类型映射;
- 用户、登录、接口或节点相关的本地映射;
- 其他由
semanage管理的本地策略定制。
导入后,应再次导出并比较:
semanage export -f /root/selinux-backup/after-import.export
diff -u \
/root/selinux-backup/current/semanage.export \
/root/selinux-backup/after-import.export
如果差异只来自排序或版本工具格式,应逐项确认;如果出现规则缺失、路径变化或端口类型变化,不要直接进入切换测试。
布尔值不能只看当前运行状态
getsebool -a 显示的是当前状态,但当前状态并不一定代表重启后仍然有效。需要同时确认持久化配置:
getsebool -a | sort
semanage boolean -l | sort
对于应用需要的具体布尔值,应先确认服务文档和实际访问需求,再决定是否使用 setsebool -P。例如,某些应用需要允许特定域进行网络连接,但不应为了“先让服务跑起来”而批量开启所有宽松选项。
setsebool -P on
这类命令会修改持久化安全策略,执行前应保留备份,并在备用机上完成服务测试。回滚时应根据备份中的原始值恢复,而不是笼统地关闭 SELinux。
自定义策略模块要单独同步
semanage export 不等于完整导出所有自定义策略模块。通过 semodule 安装的模块,需要单独确认:
semodule -lfull
主备同步时,至少应保存以下信息:
- 模块名称;
- 模块版本;
- 模块优先级;
.pp文件或可重复构建的源代码;- 模块文件的校验值;
- 模块对应的应用版本和变更原因。
例如,将经过审核的策略模块放到备用机后:
sha256sum /root/selinux-policy/custom_app.pp
semodule -i /root/selinux-policy/custom_app.pp
semodule -lfull | grep -F custom_app
如果主机上的模块文件已经丢失,只剩下运行中的策略状态,不建议直接从活动策略目录中挑选文件复制。更稳妥的做法是找到原始 .te、.if、.fc 文件或软件包,重新构建出与主机相同的模块。否则即使模块名称相同,也可能存在版本和优先级差异。
安装模块会影响当前策略加载,应该先在备用机上测试,保留旧模块和导入前的备份。若确认新模块导致服务异常,回滚应使用原版本模块重新安装,或在明确模块名称、版本和依赖关系后执行移除操作,不要直接删除整个策略模块目录。
文件上下文决定数据目录能否被服务访问
策略规则同步后,仍要检查数据目录的安全上下文。SELinux 判断访问权限时,不只看 Linux 用户和文件权限,还会检查文件的类型标签。
先查看主机上的规则和实际标签:
semanage fcontext -l | grep -E '/srv/app|/data/app'
ls -ldZ /srv/app
find /srv/app -maxdepth 2 -type f -exec ls -lZ {} \; | head -n 30
在备用机上查看 SELinux 期望的标签:
matchpathcon /srv/app
matchpathcon /srv/app/data
ls -ldZ /srv/app /srv/app/data
如果主备使用相同路径,可以先进行不修改文件的预览:
restorecon -Rnv /srv/app/data
确认输出中的变更符合预期后,再执行实际修复:
restorecon -Rv /srv/app/data
restorecon 会修改文件的 SELinux 标签,目录较大时可能影响正在运行的服务,因此应在维护窗口执行。回滚不能简单依赖“再执行一次 restorecon”,因为原来的标签可能正是错误状态。执行前应保存 ls -lZ 结果,并确保正确的 semanage fcontext 规则已经存在。
如果需要为自定义目录建立规则,应使用 semanage fcontext,不要长期依赖 chcon:
semanage fcontext -a -t '/srv/app/data(/.*)?'
restorecon -Rv /srv/app/data
其中 必须根据应用域和策略要求确认,不能把 httpd_sys_content_t 等常见类型随意套用到所有应用目录。错误的类型可能导致服务仍然无法访问,或者扩大不必要的访问范围。
数据复制必须保留扩展属性
如果使用文件级复制同步业务数据,应确认复制方式能够保留扩展属性、ACL、硬链接和数值用户组。以 rsync 为例,可以先使用预演模式:
rsync -aHAXn --delete --numeric-ids \
/srv/app/data/ standby:/srv/app/data/
确认文件列表和删除列表正确后,再执行实际同步:
rsync -aHAX --delete --numeric-ids \
/srv/app/data/ standby:/srv/app/data/
--delete 会删除备用机目标目录中源端不存在的文件,属于有影响的操作。执行前应确认源目录、目标目录、数据冻结状态和备份可用性;如果业务不允许删除,应去掉该参数或改用带版本保留的同步方式。
-X 用于保留扩展属性,其中可能包含 security.selinux。但即使复制保留了标签,也要确认备用机的策略包和路径完全一致。如果底层复制机制不会传输 SELinux 扩展属性,就应在备用机完成复制后,根据已同步的 fcontext 规则执行 restorecon。
服务端口、网络路径和健康检查要分别验证
端口监听和 SELinux 端口类型是两个不同层面的条件。先看服务实际监听情况:
ss -lntp
再查看 SELinux 端口映射:
semanage port -l
如果应用使用非标准端口,必须确认该端口已映射到应用允许的类型。下面只是操作形式示例,具体类型应以应用策略为准:
semanage port -a -t http_port_t -p tcp 8080
执行新增或修改端口规则前,应确认该端口没有已有映射,并保存导入前的 semanage 备份。错误的端口类型会导致服务仍被拒绝,删除或修改端口规则也可能影响其他服务。
主备切换时,服务访问、数据同步、心跳和管理入口不应全部依赖同一个故障点。至少要确保主服务访问路径不可用时,仍有独立的管理或控制台入口可以完成接管;数据同步链路中断时,应能明确判断数据是否已经追平,而不是仅根据网络连通性判断切换成功。
健康检查也不能只看 TCP 端口是否打开。端口开放只能说明有进程监听,不能证明服务进程能读取数据、访问必要目录或完成一次真实请求。切换测试应至少包含:
systemctl is-active .service
systemctl status .service --no-pager
ss -lntp
journalctl -b -u .service --no-pager -n 100
如果是提供 HTTP 服务的应用,还应从实际访问路径发起一次受控请求;如果是其他协议,则使用该协议对应的业务级检查。测试结束后,应确认服务仍处于 Enforcing 模式,而不是因为故障排查被留在宽松模式。
启用 Enforcing 时的验证和回滚
先确认配置文件当前值:
grep -E '^(SELINUX|SELINUXTYPE)=' /etc/selinux/config
CentOS 7.9 常见配置如下,但应以实际策略类型为准:
SELINUX=enforcing
SELINUXTYPE=targeted
如果当前已经是 permissive,可以在维护窗口内临时切换运行状态:
setenforce 1
getenforce
如果当前为 disabled,不能依靠 setenforce 立即启用,需修改 /etc/selinux/config 后重启,并提前确认备用机具备控制台入口和启动后验证条件。
切换到强制模式后,立即检查服务和审计日志:
getenforce
systemctl is-active .service
ausearch -m AVC,USER_AVC -ts recent -i
出现 AVC 拒绝时,先按以下方式判断:
| 现象 | 更可能的原因 | 优先处理方式 |
|---|---|---|
| 只有备用机出现 AVC | 策略、模块、布尔值或文件标签漂移 | 对比 semanage export、semodule -lfull 和 ls -Z |
| 主备都出现同类 AVC | 应用确实缺少必要策略或访问方式不受支持 | 审核应用访问模型,再设计最小规则 |
目录访问被拒绝,tcontext 不符合预期 | 文件上下文错误 | 检查 semanage fcontext,预览后执行 restorecon |
| 连接端口被拒绝 | SELinux 端口类型或服务监听配置不一致 | 检查 ss -lntp 和 semanage port -l |
| 没有 AVC,但服务未启动 | 应用配置、数据状态、依赖服务或网络路径问题 | 查看 systemctl 和 journalctl,不要继续放宽策略 |
| 开启宽松模式后服务恢复 | 只能说明强制访问控制阻断了某个动作 | 继续定位具体 AVC,不应长期关闭 SELinux |
不要看到 AVC 就直接使用 audit2allow 生成并安装新模块。日志中可能包含应用配置错误、路径标签错误或不应被允许的访问行为。只有在确认访问确实符合业务需求,并经过最小权限审核后,才考虑制作新的策略模块。
如果强制模式导致业务无法恢复,可以在具备控制台或受控维护入口的前提下临时执行:
setenforce 0
这只是应急回退,会降低安全边界,不应作为最终方案。恢复业务后,应保留 AVC 日志、修正策略或标签,再重新执行 setenforce 1。如果已经修改了 /etc/selinux/config,还要同步检查配置是否会在下次重启时再次进入不合适的模式。
把主备切换固定成可重复的动作
一次完整的切换演练不应只验证“备用机能否启动服务”,还要验证策略和数据是否同步完成。推荐按以下顺序执行:
- 确认主机仍可管理,保存主备双方的
sestatus、策略包版本和semanage export。 - 暂停主机写入,或确认数据复制已经追平,避免主备同时接受写请求。
- 隔离原主机的业务入口,防止切换期间形成双主。
- 在备用机确认
getenforce为Enforcing,并检查策略模块、布尔值、端口映射和目录标签。 - 按既定顺序提升数据服务和应用服务,检查服务状态及业务级健康检查。
- 从实际访问路径验证读写、认证、日志和关键数据目录。
- 持续观察
journalctl、审计日志和复制状态,确认没有新的 AVC 或数据追赶异常。 - 切换完成后重新导出备用机策略,作为下一次主备校准的基线。
这里需要特别区分三个时间指标:策略同步延迟、业务数据复制延迟和人工切换耗时。SELinux 本地配置通常不需要按秒级实时复制,但每次策略变更后都应及时同步;业务数据则可能需要更高频率复制;人工确认、隔离旧主机和业务验证会直接影响实际切换时间。
根据切换要求选择维护方式
如果业务要求较短的恢复时间,备用机应保持为可启动的热备用状态,提前安装相同策略包和应用版本,持续同步策略导出文件及自定义模块,并定期进行强制模式下的切换演练。这样需要投入额外的备用资源、数据复制能力和自动化校验,但可以明显减少临时修改策略的步骤。
如果业务允许较长的恢复时间,可以采用定期导出、人工导入和按计划演练的方式。成本较低,但必须接受策略漂移和人工操作带来的切换风险,尤其不能把“多年未启动的备用机”直接视为可用备用机。
如果主备目录结构不同、应用角色不同或策略模块没有源文件,则不适合直接复制主机策略。应分别维护每台服务器的 fcontext、端口和模块映射,并在每次应用变更后重新验证。若无法提供控制台入口、策略备份和数据回滚能力,也不应在没有演练的情况下把 SELinux 从宽松模式直接切换为强制模式。
最终可以按这条路径判断:主备版本和路径一致,就同步策略包、semanage 导出内容、模块文件和数据标签;路径或角色不同,就只同步通用策略,把文件上下文和端口规则按备用机实际环境重新定义;切换前若发现 AVC 只存在于备用机,先处理策略漂移;若主备都出现同类 AVC,则需要重新审核应用访问模型。这样,SELinux 不会成为主备切换时的临时变量,而会成为两台服务器共同遵守、可验证并可回滚的安全基线。
