Linux SELinux 安全模块实战:原理、模式切换、布尔值与排错指南


<!DOCTYPE html>

Linux SELinux 安全模块实战:原理、模式切换、布尔值与排错指南

很多站长拿到新 VPS 后的第一件事,就是照着网上的"优化教程"把 SELinux 关掉。理由无非是"影响性能""配置太麻烦""关了省事"。但 SELinux 是 Linux 内核级的强制访问控制(MAC)机制,是纵深防御里非常重要的一层。真正的问题不是 SELinux 本身难用,而是我们不了解它。这篇文章不讲玄学,直接从原理讲到实战排错,让你能放心地把 SELinux 开起来,并且遇到问题能在十分钟内定位、修复。

一、SELinux 是什么:三个必须搞懂的核心概念

传统 Linux 权限(rwx)属于自主访问控制(DAC):文件的所有者可以任意修改自己的权限。而 SELinux 属于强制访问控制(MAC):即使是 root,也要遵守策略里定义好的规则。理解 SELinux 只需要抓住三个概念:主体、客体和类型强制。

  • 主体(Subject):发起访问的进程,比如 Nginx、SSHD。
  • 客体(Object):被访问的资源,比如文件、目录、端口、Socket。
  • 类型强制(Type Enforcement):SELinux 给主体和客体都打上"类型标签",规则描述"哪个类型的主体可以访问哪个类型的客体"。

在 CentOS / AlmaLinux / Rocky Linux 上,先确认当前状态:

# 查看 SELinux 状态(模式 + 策略类型)
sestatus

# 更简单的命令,只输出当前模式
getenforce

输出大致如下:

SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing

这里的 targeted 是默认策略:只对网络服务(httpd、sshd、named 等)进行约束,普通用户进程基本不受影响,这也是它性能开销极低的原因。

二、三种模式与切换:enforcing / permissive / disabled

SELinux 有三种模式,很多新手把 permissive 和 disabled 搞混:

  • enforcing(强制):违反策略的操作被直接拒绝,并写入审计日志。生产环境应该用这个。
  • permissive(宽容):违反策略的操作不拦截,只记录日志。这是排错时的"调试模式"。
  • disabled(禁用):SELinux 完全不加载,连标签都不打。想重新启用必须改配置后重启。

临时切换模式(重启后失效):

# 切到 permissive,只记日志不拦截
setenforce 0

# 切回 enforcing
setenforce 1

# 查看当前是否生效
getenforce

永久修改写入 /etc/selinux/config:

# 修改这一行为 enforcing / permissive / disabled
SELINUX=enforcing

# 修改后必须重启才生效
reboot

排错要点:如果你的 SELinux 是 disabled 状态,直接 setenforce 1 会报错 setenforce: SELinux is disabled。此时必须修改配置文件并重启系统才能重新启用。反过来,只把模式设为 permissive 而不设为 disabled,就能保留完整的标签信息,方便排查。

三、文件与进程标签:ls -Z 与 restorecon

SELinux 一切规则都围绕"标签"展开。文件有文件标签,进程有进程标签。查看标签要用带 -Z 的选项:

# 查看文件的 SELinux 标签
ls -Z /usr/share/nginx/html/index.html

# 查看进程的 SELinux 标签
ps -Z | grep nginx

# 查看端口上下文
semanage port -l | grep http

输出类似:

system_u:object_r:httpd_sys_content_t:s0 /usr/share/nginx/html/index.html
system_u:system_r:httpd_t:s0    12345 ?  00:00:00 nginx

标签格式为 用户:角色:类型:级别,其中最重要的是第三段的类型。进程类型是 httpd_t,它能读的类型是 httpd_sys_content_t(静态内容)、httpd_sys_rw_content_t(可读写内容)等。

当站点目录被放到自定义位置(比如 /data/www)时,新目录没有正确的标签,Nginx 就会 403。修复命令:

# 1. 给目录定义默认标签规则(永久生效)
semanage fcontext -a -t httpd_sys_content_t "/data/www(/.*)?"

# 2. 重新应用标签(把现有文件的标签刷成规则定义的值)
restorecon -Rv /data/www

# 3. 确认标签已经正确
ls -Zd /data/www

restorecon 按 fcontext 里登记的规则还原标签,是最安全的修法;chcon 只是临时改标签,重启或执行 restorecon 后会被还原,不建议依赖它。

四、布尔值开关:不写规则也能放行

很多常见需求(比如让 Nginx 反向代理时主动连接后端端口、连接数据库)SELinux 已经预置了开关,叫"布尔值"(boolean)。开开关比写自定义策略简单得多:

# 列出所有布尔值
getsebool -a

# 只看 httpd 相关的
getsebool -a | grep httpd

# 临时开启(重启后失效)
setsebool httpd_can_network_connect on

# 永久开启(-P 参数,写入策略,重启保留)
setsebool -P httpd_can_network_connect on

# 查看某个布尔值当前状态
getsebool httpd_can_network_connect

几个高频使用的布尔值:

# Nginx 作为反代连接后端端口
setsebool -P httpd_can_network_connect on

# 连接 MySQL / PostgreSQL
setsebool -P httpd_can_network_connect_db on

# 允许读写用户主目录(如 /home 下的站点)
setsebool -P httpd_read_user_content on
setsebool -P httpd_enable_home_dirs on

# 允许通过 NFS / CIFS 挂载点提供内容
setsebool -P httpd_use_nfs on
setsebool -P httpd_use_cifs on

排错要点:反代连不上后端、PHP 连不上数据库,先别急着改 iptables,用 getsebool 检查对应的布尔值往往一秒解决。

五、实战排错:Nginx 站点 403 的完整定位流程

下面演示一个真实场景:把站点从 /usr/share/nginx/html 挪到 /data/www/blog 后,浏览器访问直接 403。先确认不是权限问题:

# 权限和属主都正常
ls -ld /data/www/blog
# drwxr-xr-x root root /data/www/blog

那八成是 SELinux 标签不对。第一步,确认当前模式和是否有 AVC 拒绝日志:

# 查看最近 10 分钟内的 AVC 拒绝记录
ausearch -m AVC -ts recent

# 只查 httpd 相关的拒绝
ausearch -m AVC -c httpd -ts recent

会看到类似这样的记录:

type=AVC msg=audit(1699000000.123:456): avc:  denied  { read } for  pid=12345
  comm="nginx" name="index.html" dev="vda1" ino=67890
  scontext=system_u:system_r:httpd_t:s0
  tcontext=unconfined_u:object_r:default_t:s0
  tclass=file permissive=0

关键在最后三行:主体 httpd_t 想读类型为 default_t 的文件被拒绝。说明新目录继承了默认标签而不是 httpd_sys_content_t。用 audit2why 还能给出修复建议:

ausearch -m AVC -ts recent | audit2why

修复就是第三节的方法,重新定义标签:

semanage fcontext -a -t httpd_sys_content_t "/data/www(/.*)?"
restorecon -Rv /data/www

如果 Nginx 还要写文件(比如上传目录、FastCGI 缓存),把这个目录的类型换成可写类型:

# 上传目录需要可读写
semanage fcontext -a -t httpd_sys_rw_content_t "/data/www/blog/wp-content(/.*)?"
restorecon -Rv /data/www/blog/wp-content

# FastCGI 缓存目录
semanage fcontext -a -t httpd_cache_t "/var/cache/nginx(/.*)?"
restorecon -Rv /var/cache/nginx

六、实战排错:绑定非标准端口被拒

Nginx 监听 8080 端口启动失败,日志里却没有任何配置错误,多半也是 SELinux:策略默认只允许 httpd 监听 80、443 等标准端口,其余端口需要显式登记。报错信息可在审计日志中确认:

ausearch -m AVC -c nginx -ts recent

# 或者直接看 systemd 日志
journalctl -u nginx --no-pager | tail -30

修复:把端口登记到 http_port_t 类型下:

# 永久登记端口
semanage port -a -t http_port_t -p tcp 8080

# 查看当前已登记的 http 端口
semanage port -l | grep http_port_t

# 删除不再需要的登记
semanage port -d -t http_port_t -p tcp 8080

同理,SSH 改了非标准端口连不上时,用 semanage port -a -t ssh_port_t -p tcp 2222 即可。

七、排错方法论:三步定位法

遇到任何 SELinux 相关问题,按下面三步走,基本不会绕弯路:

  1. 确认模式:getenforce。permissive 下还出问题,那根本不是 SELinux 拦截,回去查权限、防火墙、配置。
  2. 查 AVC 日志:ausearch -m AVC -ts recent 或 journalctl | grep "avc:"。没有记录就继续查别的原因。
  3. 对症修复:按拒绝记录里给出的主体和客体类型,选择 semanage fcontext + restorecon、setsebool 或 semanage port 三件套中的对应工具。

几个容易踩的坑:

  • 不要用 setenforce 0 长期运行,那是调试手段不是运维方案。
  • chcon 改的标签在 restorecon 或系统重启后会被刷掉,要持久化必须用 semanage fcontext。
  • 改了 /etc/selinux/config 后必须重启,setenforce 改不了 disabled 状态。
  • CentOS 8+ 默认安装了 container-selinux,Docker 无法启动时先 rpm -qa | grep selinux 看策略包是否齐全。

八、常用命令速查表

sestatus                          # 查看整体状态
getenforce                        # 查看当前模式
setenforce 0|1                    # 临时切换 permissive/enforcing
getsebool -a                      # 列出全部布尔值
setsebool -P 布尔值 on            # 永久开启布尔值
ls -Z 路径                        # 查看文件标签
ps -Z                             # 查看进程标签
restorecon -Rv 目录               # 按规则还原目录标签
chcon -t 类型 文件                # 临时修改标签
semanage fcontext -l              # 列出自定义标签规则
semanage fcontext -a -t 类型 "路径"   # 新增标签规则
semanage port -l                  # 列出端口上下文
semanage port -a -t 类型 -p tcp 端口  # 登记端口
ausearch -m AVC -ts recent        # 查最近的 AVC 拒绝
audit2why                          # 分析拒绝原因并给建议

SELinux 不是"关掉就完事"的麻烦,而是 Linux 安全模型的最后一道防线。把常用的几个布尔值和 semanage fcontext 用熟,它带来的安全收益远大于配置成本。下次再看到"请先关闭 SELinux"的教程,你可以放心地把那条命令划掉。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

Linux crontab 定时任务实战:计划任务配置、日志排查与自动化运维指南

Linux 日志轮转 logrotate 进阶实战:配置、压缩与排错指南

评 论
更换验证码