SELinux 企业级入门与实战教程:不要再一键关闭 SELinux

欢迎你来读这篇博客,这篇博客主要是关于 SELinux 企业级入门与实战

很多 Linux 教程遇到 SELinux 报错时,第一反应就是:

1
2
setenforce 0
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config

这样做确实很快,快到就像把小区门禁拆了,外卖进来了,陌生人也进来了。

在个人实验环境里,这种做法可能只是偷懒;但在企业服务器、数据库服务器、Web 服务器、容器宿主机、Kubernetes 节点上,直接关闭 SELinux 通常不是解决问题,而是绕过问题。

本文会从零开始讲清楚 SELinux 的核心概念、常用命令、文件上下文、端口上下文、Boolean、audit 日志、排错流程、Web 服务示例、容器场景以及企业落地 Checklist。

序言

SELinux,全称是 Security-Enhanced Linux,是一套 Linux 强制访问控制机制。

传统 Linux 权限主要依赖 DAC,也就是自主访问控制,例如:

1
2
3
4
5
6
chmod
chown
rwx
user
group
other

这些权限很重要,但它们有一个问题:只要进程拿到了某个用户的权限,就可以访问这个用户能访问的大量资源。

例如 Web 服务被攻破后,攻击者可能借助 nginxapachetomcatjava 进程读取不该读的文件、连接不该连接的端口、写入不该写入的目录。

SELinux 的价值就在这里:

即使一个进程被攻破,它也不一定能做它想做的事情。

SELinux 不只看 Linux 传统权限,还会看安全上下文、进程域、文件类型、端口类型、策略规则。

所以 SELinux 的思路不是:

这个文件是不是 777

而是:

这个进程域,是否被策略允许访问这个资源类型?

这就是很多人第一次接触 SELinux 时觉得它“玄学”的原因。

其实它不是玄学,它只是比 chmod 777 更认真。认真到有点像保安队长拿着花名册逐个核验,烦,但有用。

正文

第一章:为什么不要直接关闭 SELinux

1.1 关闭 SELinux 的常见理由

很多教程会建议关闭 SELinux,理由通常有几个:

  • 服务启动失败;
  • 文件明明有权限,却访问不了;
  • Nginx / Apache 读不到目录;
  • 数据库写不了自定义目录;
  • 容器挂载目录后权限异常;
  • 自定义端口无法监听;
  • 排查成本高,不如直接关闭。

这些问题确实常见,但结论不应该是关闭 SELinux。

更合理的做法是:

  1. 先确认是否真是 SELinux 拦截;
  2. 再确认是文件标签问题、端口标签问题、Boolean 问题,还是策略缺失;
  3. 最后用最小权限方式修复。

1.2 企业环境为什么建议保持 Enforcing

企业服务器上,SELinux 至少能带来这些价值:

  • 限制服务被攻破后的横向移动;
  • 限制 Web 服务读取系统敏感文件;
  • 限制服务访问非授权目录;
  • 限制服务监听非授权端口;
  • 配合 auditd 提供审计证据;
  • 配合容器 Label 降低宿主机目录暴露风险;
  • 满足安全基线、等保、CIS Benchmark 等要求。

生产环境推荐:

1
SELINUX=enforcing

开发调试环境可以临时:

1
sudo setenforce 0

但不建议永久:

1
SELINUX=disabled

1.3 三种状态的区别

SELinux 常见状态有三种:

状态 含义 是否推荐生产使用
Enforcing 强制执行策略,违规行为会被拒绝并记录日志 推荐
Permissive 不拒绝违规行为,只记录日志 可用于调试
Disabled 完全关闭 SELinux,不打标签或不执行策略 不推荐

一个重要细节:

Disabled 不是更干净,而是更麻烦。

如果系统长期处于 Disabled,后续重新开启 SELinux 时,很多文件可能没有正确标签,容易导致服务异常甚至启动问题。

正确做法是:

  • 调试时用 Permissive;
  • 生产时用 Enforcing;
  • 尽量不要 Disabled。

第二章:SELinux 的核心模型

2.1 DAC 与 MAC

传统 Linux 权限属于 DAC:Discretionary Access Control,自主访问控制。

例如:

1
ls -l /data/www/index.html

输出可能是:

1
-rw-r--r-- 1 root root 1024 Jun 30 12:00 index.html

这表示:

  • owner 可以读写;
  • group 可以读;
  • other 可以读。

SELinux 属于 MAC:Mandatory Access Control,强制访问控制。

它不会只看 rwx,还会看安全上下文。

查看安全上下文:

1
ls -Z /data/www/index.html

可能看到:

1
system_u:object_r:httpd_sys_content_t:s0 /data/www/index.html

这串内容就是 SELinux 判断权限的重要依据。

2.2 Subject 与 Object

SELinux 里可以简单理解为:

概念 说明 示例
Subject 主体,通常是进程 httpdnginxsshdmysqld
Object 客体,被访问的资源 文件、目录、端口、socket、设备

例如:

1
httpd 进程 访问 /var/www/html/index.html

这里:

  • httpd 进程是 Subject;
  • index.html 是 Object;
  • SELinux 判断 httpd_t 是否可以访问 httpd_sys_content_t

2.3 安全上下文结构

SELinux 安全上下文一般长这样:

1
user:role:type:level

示例:

1
system_u:object_r:httpd_sys_content_t:s0

可以拆成:

字段 示例 说明
user system_u SELinux 用户
role object_r SELinux 角色
type httpd_sys_content_t 类型,最常用、最关键
level s0 MLS/MCS 级别

日常运维中,最常处理的是 type

这也是 SELinux 里最重要的思想:

Type Enforcement,类型强制。

2.4 进程域与文件类型

查看进程上下文:

1
ps -eZ | grep httpd

可能看到:

1
system_u:system_r:httpd_t:s0  1234 ?  00:00:00 httpd

这里的 httpd_t 是进程域。

查看文件上下文:

1
ls -Z /var/www/html

可能看到:

1
system_u:object_r:httpd_sys_content_t:s0 index.html

这里的 httpd_sys_content_t 是文件类型。

策略表达的是:

1
httpd_t 是否可以 read/open/getattr httpd_sys_content_t 类型的文件?

这比 chmod 777 精细得多。

第三章:安装 SELinux 常用工具

3.1 基础包

Rocky Linux / RHEL 系发行版一般默认启用 SELinux,但很多管理工具可能没有安装完整。

建议安装:

1
2
3
4
5
6
7
8
sudo dnf install -y \
policycoreutils \
policycoreutils-python-utils \
selinux-policy \
selinux-policy-targeted \
setroubleshoot-server \
setools-console \
audit

说明:

作用
policycoreutils 提供 SELinux 基础工具
policycoreutils-python-utils 提供 semanage 等常用命令
selinux-policy-targeted targeted 策略
setroubleshoot-server 提供 sealert 分析工具
setools-console 提供 sesearch 等策略查询工具
audit 提供 auditd 审计日志

3.2 启动 auditd

SELinux 拒绝日志通常会进入 audit 日志。

建议开启 auditd:

1
2
sudo systemctl enable --now auditd
sudo systemctl status auditd

查看 audit 日志:

1
sudo tail -f /var/log/audit/audit.log

如果没有 auditd,有些 SELinux 消息可能只能从 dmesg 或 journal 中查,排查体验会差很多。

第四章:查看和切换 SELinux 状态

4.1 查看当前模式

最常用:

1
getenforce

可能输出:

1
Enforcing

完整查看:

1
sestatus

示例输出:

1
2
3
4
5
6
7
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
Policy MLS status: enabled

4.2 临时切换为 Permissive

1
2
sudo setenforce 0
getenforce

输出:

1
Permissive

这表示:

  • SELinux 不再阻止访问;
  • 但仍然记录违规日志;
  • 适合排查问题。

4.3 临时切换回 Enforcing

1
2
sudo setenforce 1
getenforce

输出:

1
Enforcing

4.4 永久配置

配置文件:

1
sudo vim /etc/selinux/config

推荐生产配置:

1
2
SELINUX=enforcing
SELINUXTYPE=targeted

调试期可以临时:

1
2
SELINUX=permissive
SELINUXTYPE=targeted

不推荐:

1
SELINUX=disabled

修改配置文件后需要重启才能完全生效:

1
sudo reboot

4.5 从 Disabled 恢复到 Enforcing 的正确姿势

如果系统之前是 Disabled,不要直接改成 Enforcing 然后重启。

更安全的流程是:

1
sudo vim /etc/selinux/config

先设置:

1
SELINUX=permissive

然后触发重新打标签:

1
2
sudo fixfiles -F onboot
sudo reboot

或者:

1
2
sudo touch /.autorelabel
sudo reboot

重启后检查 AVC 拒绝日志,确认没有问题,再切换到 Enforcing:

1
2
sudo setenforce 1
sudo sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config

注意:

长期 Disabled 后重新开启 SELinux,最容易出问题的不是 SELinux 本身,而是系统里已经堆了一堆没有正确标签的文件。

第五章:查看 SELinux 上下文

5.1 查看用户上下文

1
id -Z

示例:

1
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

5.2 查看文件上下文

1
2
ls -Z
ls -Zd /var/www/html

示例:

1
system_u:object_r:httpd_sys_content_t:s0 index.html

5.3 查看进程上下文

1
2
3
ps -eZ | grep sshd
ps -eZ | grep nginx
ps -eZ | grep httpd

5.4 查看端口上下文

1
2
sudo semanage port -l | grep http
sudo semanage port -l | grep ssh

示例:

1
2
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443
ssh_port_t tcp 22

5.5 查看路径默认上下文

1
2
matchpathcon /var/www/html
matchpathcon /data/www

matchpathcon 可以告诉你某个路径根据当前策略应该是什么上下文。

第六章:文件上下文管理

6.1 文件权限没问题,为什么服务还是读不了?

假设你把网站目录放到了 /data/www

1
2
sudo mkdir -p /data/www
sudo echo 'hello selinux' | sudo tee /data/www/index.html

传统权限看起来可能没问题:

1
ls -l /data/www

但 Apache/Nginx 仍然访问失败。

这时要看 SELinux 上下文:

1
2
ls -Zd /data/www
ls -Z /data/www

如果看到类似:

1
2
default_t
var_t

那大概率是标签不对。

Web 服务通常不能随便读取 default_tvar_t 类型的文件。

6.2 chcon:临时修改上下文

可以临时修改:

1
sudo chcon -R -t httpd_sys_content_t /data/www

但不推荐作为长期方案。

原因是:

1
sudo restorecon -Rv /data/www

可能会把 chcon 改过的标签恢复掉。

6.3 semanage fcontext:永久规则

正确做法是添加永久文件上下文规则:

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

解释:

命令 作用
semanage fcontext -a 添加文件上下文规则
-t httpd_sys_content_t 设置类型为 Web 静态内容类型
"/data/www(/.*)?" 匹配目录及其所有子文件
restorecon -Rv 按规则重新打标签

6.4 修改已有规则

如果规则已经存在,可以用:

1
sudo semanage fcontext -m -t httpd_sys_content_t "/data/www(/.*)?"

6.5 删除规则

1
sudo semanage fcontext -d "/data/www(/.*)?"

删除后重新打标签:

1
sudo restorecon -Rv /data/www

6.6 查看自定义文件上下文规则

1
sudo semanage fcontext -l | grep /data/www

6.7 Web 可写目录不要乱给

如果只是静态页面:

1
httpd_sys_content_t

如果某个目录需要 Web 服务写入,例如上传目录:

1
2
3
sudo mkdir -p /data/www/uploads
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/data/www/uploads(/.*)?"
sudo restorecon -Rv /data/www/uploads

不要把整个站点都设置成可写。

错误示范:

1
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/data/www(/.*)?"

除非你真的希望整个站点目录都能被 Web 服务写入。

企业建议:

能只读就只读,能局部可写就不要全局可写。

第七章:端口上下文管理

7.1 为什么服务监听自定义端口会失败

假设你把 SSH 改成 2222:

1
Port 2222

然后重启 sshd:

1
sudo systemctl restart sshd

可能失败。

传统防火墙放行了,配置文件也没错,但 SELinux 仍然可能阻止 sshd_t 绑定非 ssh_port_t 类型的端口。

7.2 查看 SSH 允许端口

1
sudo semanage port -l | grep ssh

通常看到:

1
ssh_port_t tcp 22

7.3 添加 SSH 自定义端口

1
sudo semanage port -a -t ssh_port_t -p tcp 2222

然后重启 sshd:

1
sudo systemctl restart sshd

同时别忘了 firewalld:

1
2
sudo firewall-cmd --add-port=2222/tcp --permanent
sudo firewall-cmd --reload

7.4 修改已有端口类型

如果端口已经被其他类型占用,-a 会失败。

可以先查:

1
sudo semanage port -l | grep 8080

修改:

1
sudo semanage port -m -t http_port_t -p tcp 8080

7.5 删除端口规则

1
sudo semanage port -d -t ssh_port_t -p tcp 2222

7.6 Web 服务自定义端口示例

假设 Apache/Nginx 使用 8081:

1
2
3
sudo semanage port -a -t http_port_t -p tcp 8081
sudo firewall-cmd --add-port=8081/tcp --permanent
sudo firewall-cmd --reload

企业排错口诀:

服务自定义端口 = 配置文件 + firewalld + SELinux port context,三处都要看。

第八章:SELinux Boolean

8.1 Boolean 是什么

SELinux Boolean 可以理解成策略里的开关。

它允许你不写策略模块,也能开启某些受控能力。

例如:

  • 允许 httpd 访问用户 home 目录;
  • 允许 httpd 主动连接网络;
  • 允许 Samba 访问某些目录;
  • 允许服务访问 NFS。

8.2 查看 Boolean

查看所有:

1
getsebool -a

过滤 httpd:

1
getsebool -a | grep httpd

更详细:

1
sudo semanage boolean -l | grep httpd

8.3 临时修改 Boolean

1
sudo setsebool httpd_can_network_connect on

临时修改重启后可能失效。

8.4 永久修改 Boolean

1
sudo setsebool -P httpd_can_network_connect on

-P 表示持久化。

8.5 常见 Boolean 示例

场景 Boolean
httpd 需要主动访问后端服务 httpd_can_network_connect
httpd 连接数据库 httpd_can_network_connect_db
httpd 访问用户 home httpd_enable_homedirs
httpd 访问 NFS httpd_use_nfs
httpd 访问 Samba/CIFS httpd_use_cifs
FTP 访问用户 home ftp_home_dir

注意:

Boolean 不是越开越好。每开一个开关,都是在扩大服务能力边界。

企业建议:

  • 先确认需求;
  • 再查是否有对应 Boolean;
  • 只开启必要 Boolean;
  • 开启前后记录变更;
  • 不要照抄“全部打开”。

第九章:SELinux 日志与排错

9.1 常见报错现象

SELinux 拦截时,应用层可能只看到普通错误:

1
2
3
4
5
Permission denied
13: Permission denied
Unable to open file
bind: Permission denied
connect() failed

这些报错不一定是 Linux 文件权限问题,也可能是 SELinux 拦截。

9.2 查看 audit 日志

1
sudo ausearch -m AVC -ts recent

查看今天的 AVC:

1
sudo ausearch -m AVC -ts today

查看最近 10 分钟:

1
sudo ausearch -m AVC -ts recent

直接 grep:

1
sudo grep AVC /var/log/audit/audit.log

9.3 使用 sealert 分析

1
sudo sealert -a /var/log/audit/audit.log

或者根据日志里的编号分析。

sealert 会给出解释和可能的修复建议。

但要注意:

不要看到 audit2allow 建议就立刻生成策略模块。企业排错时,应该先检查标签、端口、Boolean。

9.4 没有 auditd 时怎么办

可以查:

1
2
sudo dmesg | grep -i denied
sudo journalctl | grep -i avc

但还是建议安装并启动 auditd。

9.5 SELinux 排错优先级

推荐顺序:

1
2
3
4
5
6
7
8
1. 确认 SELinux 是否真的相关
2. 查看 AVC 日志
3. 检查文件上下文是否错误
4. 检查端口上下文是否错误
5. 检查是否需要 Boolean
6. 检查服务是否使用了非标准目录
7. 检查是否需要恢复标签 restorecon
8. 最后才考虑自定义 policy module

别一上来就:

1
2
audit2allow -M mypolicy
semodule -i mypolicy.pp

这就像家里门锁卡住了,第一反应不是修锁,而是把整扇门拆了。

第十章:audit2allow 与自定义策略模块

10.1 audit2allow 是什么

audit2allow 可以根据 audit 日志生成 SELinux allow 规则。

它很强,但也很危险。

因为它只知道“刚才被拒绝了什么”,不一定知道“这件事是否应该被允许”。

10.2 什么时候可以考虑使用 audit2allow

可以考虑的场景:

  • 自研服务没有现成策略;
  • 使用了特殊部署结构;
  • 已确认不是文件标签问题;
  • 已确认不是端口类型问题;
  • 已确认没有合适 Boolean;
  • 规则经过人工 review;
  • 策略模块纳入版本管理。

10.3 生成策略模块

示例:

1
sudo ausearch -m AVC -ts recent --raw | audit2allow -M myapp_local

会生成:

1
2
myapp_local.te
myapp_local.pp

查看 .te 文件:

1
cat myapp_local.te

确认规则合理后再安装:

1
sudo semodule -i myapp_local.pp

10.4 查看策略模块

1
sudo semodule -l | grep myapp

10.5 删除策略模块

1
sudo semodule -r myapp_local

10.6 企业建议

不要把 audit2allow 当成自动修复神器。

正确流程:

1
日志分析 -> 人工判断 -> 最小授权 -> 策略审查 -> 测试验证 -> 版本管理 -> 生产发布

策略模块命名建议:

1
company_appname_reason_version

例如:

1
acme_order_service_logwrite_v1

第十一章:Apache / Nginx 自定义目录实战

这一章用 Web 服务举例,因为这是 SELinux 最常见的问题之一。

11.1 安装 httpd

1
2
sudo dnf install -y httpd
sudo systemctl enable --now httpd

确认运行:

1
systemctl status httpd

11.2 默认目录为什么没问题

Apache 默认目录:

1
/var/www/html

查看上下文:

1
ls -Zd /var/www/html

通常是:

1
system_u:object_r:httpd_sys_content_t:s0 /var/www/html

所以 Apache 可以读取。

11.3 自定义目录 /data/www

创建目录:

1
2
3
4
sudo mkdir -p /data/www
sudo tee /data/www/index.html <<EOF
hello selinux
EOF

配置 Apache 指向 /data/www 后,可能访问失败。

查看上下文:

1
ls -Zd /data/www

如果不是 httpd_sys_content_t,就需要添加规则。

11.4 正确修复

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

验证:

1
2
ls -Zd /data/www
ls -Z /data/www

11.5 上传目录可写

假设上传目录是:

1
/data/www/uploads

执行:

1
2
3
sudo mkdir -p /data/www/uploads
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/data/www/uploads(/.*)?"
sudo restorecon -Rv /data/www/uploads

这样只有 uploads 可写,其他目录仍然只读。

11.6 Web 服务需要访问后端接口

如果应用需要由 httpd/nginx 代理访问后端服务,可能需要:

1
sudo setsebool -P httpd_can_network_connect on

如果连接数据库,可能需要:

1
sudo setsebool -P httpd_can_network_connect_db on

开启前请确认确实需要。

第十二章:SSH 修改端口实战

12.1 修改 sshd_config

1
sudo vim /etc/ssh/sshd_config

配置:

1
2
3
4
Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

12.2 SELinux 添加端口

1
sudo semanage port -a -t ssh_port_t -p tcp 2222

如果提示端口已定义,先查:

1
sudo semanage port -l | grep 2222

12.3 firewalld 放行

1
2
sudo firewall-cmd --add-port=2222/tcp --permanent
sudo firewall-cmd --reload

12.4 测试配置

1
2
sudo sshd -t
sudo systemctl restart sshd

12.5 防止锁死

不要关掉当前 SSH 会话。

重新开一个终端测试:

1
ssh -p 2222 user@server-ip

确认可以登录后,再关闭旧会话。

第十三章:Podman / Docker 容器与 SELinux

13.1 容器为什么经常遇到 SELinux 问题

容器挂载宿主机目录时,传统权限可能没问题,但 SELinux 标签不匹配。

例如:

1
podman run -v /data/nginx:/usr/share/nginx/html nginx

容器里可能读不到文件。

13.2 使用 :Z 和 :z

Podman / Docker 在 SELinux 环境下常用挂载参数:

参数 含义 场景
:Z 私有标签,只给当前容器使用 单容器独占目录
:z 共享标签,多个容器可共享 多容器共享目录

示例:

1
2
3
4
5
podman run -d \
--name nginx-demo \
-p 8080:80 \
-v /data/nginx:/usr/share/nginx/html:Z \
nginx

多个容器共享:

1
podman run -v /data/shared:/data:z image

13.3 不建议直接 –privileged

错误思路:

1
podman run --privileged ...

--privileged 会显著扩大容器权限,除非你非常清楚自己在做什么。

企业建议:

  • 优先使用 :Z / :z
  • 优先 rootless Podman;
  • 避免 --privileged
  • 避免随意关闭 SELinux;
  • 宿主机目录挂载要做权限和标签双重检查。

13.4 查看容器相关标签

1
2
ls -Z /data/nginx
ps -eZ | grep container

常见类型:

1
2
container_t
container_file_t

第十四章:Java 服务与 SELinux

14.1 Java 应用为什么也需要关注 SELinux

很多 Java 后端服务部署在:

1
2
3
/app/order-service
/logs/order-service
/data/order-service

这些目录不是系统默认路径。

如果服务被放入受限域,或者配合 systemd、Podman、Nginx、Apache、文件上传、日志采集等组件,SELinux 标签就会影响访问。

14.2 Java 服务目录建议

建议规划:

1
2
3
4
5
/app/order-service
/app/order-service/releases
/app/order-service/current
/logs/order-service
/data/order-service

传统权限:

1
2
sudo useradd -r -s /sbin/nologin app
sudo chown -R app:app /app/order-service /logs/order-service /data/order-service

SELinux 层面,需要根据服务运行域和访问方式判断。

14.3 被 Nginx 访问的静态目录

如果 Java 服务生成的静态文件需要被 Nginx/Apache 读取,例如:

1
/data/order-service/public

可以设置:

1
2
sudo semanage fcontext -a -t httpd_sys_content_t "/data/order-service/public(/.*)?"
sudo restorecon -Rv /data/order-service/public

如果只有上传目录需要 Web 可写:

1
2
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/data/order-service/public/uploads(/.*)?"
sudo restorecon -Rv /data/order-service/public/uploads

14.4 systemd 管理 Java 服务

systemd unit 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=Order Service
After=network.target

[Service]
User=app
Group=app
WorkingDirectory=/app/order-service/current
ExecStart=/usr/bin/java -jar /app/order-service/current/order-service.jar
Restart=always
RestartSec=10
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target

如果服务读写失败,排查顺序仍然是:

1
Linux 权限 -> SELinux AVC 日志 -> 文件标签 -> 端口标签 -> Boolean -> 自定义策略

第十五章:NFS / Samba / 共享存储场景

15.1 NFS 场景

如果 Web 服务访问 NFS 挂载目录,可能需要相关 Boolean。

示例:

1
getsebool -a | grep nfs

如果是 httpd 访问 NFS:

1
sudo setsebool -P httpd_use_nfs on

15.2 Samba / CIFS 场景

查看:

1
getsebool -a | grep cifs

如果 httpd 访问 CIFS:

1
sudo setsebool -P httpd_use_cifs on

15.3 企业建议

共享存储场景不要只看挂载是否成功,还要看:

  • 服务进程域;
  • 挂载目录标签;
  • 是否需要 Boolean;
  • 是否有 noexec/nosuid/nodev 等挂载参数;
  • 是否符合安全基线。

第十六章:SELinux 用户与登录映射

16.1 查看 SELinux 用户映射

1
sudo semanage login -l

可能看到:

1
2
3
Login Name           SELinux User         MLS/MCS Range
__default__ unconfined_u s0-s0:c0.c1023
root unconfined_u s0-s0:c0.c1023

16.2 常见 SELinux 用户

SELinux 用户 说明
unconfined_u 非受限用户,常见默认值
user_u 普通受限用户
staff_u 可切换角色的用户
sysadm_u 系统管理员相关用户

16.3 企业是否必须使用受限用户

大多数普通企业服务器,重点通常不是先改 SELinux 用户映射,而是:

  • 保持 Enforcing;
  • 正确配置服务标签;
  • 管理好端口类型;
  • 开启 auditd;
  • 控制 sudo;
  • 不滥用 unconfined 服务。

高安全场景可以进一步使用受限用户和角色切换,但实施成本更高,需要配套运维规范。

第十七章:SELinux 常见问题速查

17.1 文件权限明明对,为什么还是 Permission denied?

检查:

1
2
ls -Z /path/to/file
sudo ausearch -m AVC -ts recent

常见原因:

  • 文件类型不对;
  • 目录继承了错误标签;
  • 使用了非标准目录;
  • 没有执行 restorecon

17.2 restorecon 后为什么配置又没了?

因为你可能用了 chcon 临时改标签。

长期方案应该用:

1
2
semanage fcontext
restorecon

17.3 自定义端口为什么服务启动不了?

检查:

1
2
sudo semanage port -l | grep <port>
sudo ausearch -m AVC -ts recent

修复:

1
sudo semanage port -a -t <type> -p tcp <port>

17.4 audit2allow 能不能无脑用?

不建议。

优先级应该是:

1
标签 -> 端口 -> Boolean -> 策略模块

17.5 为什么 Disabled 后再开启容易出问题?

因为 Disabled 状态下,新文件可能没有正确 SELinux 标签。

重新开启时需要重新打标签:

1
2
sudo fixfiles -F onboot
sudo reboot

17.6 为什么容器挂载目录访问不了?

优先尝试:

1
-v /host/path:/container/path:Z

或共享目录:

1
-v /host/path:/container/path:z

不要第一反应就是 --privileged 或关闭 SELinux。

第十八章:企业级 SELinux 排错流程

建议把下面流程贴到团队 Wiki。

18.1 标准排错流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
第一步:确认现象
应用报错是什么?
是读文件失败、写文件失败、端口绑定失败,还是网络连接失败?

第二步:确认 SELinux 状态
getenforce
sestatus

第三步:临时验证是否 SELinux 相关
setenforce 0
复现问题
setenforce 1

第四步:查看 AVC 日志
ausearch -m AVC -ts recent
sealert -a /var/log/audit/audit.log

第五步:判断类型
文件上下文问题?
端口上下文问题?
Boolean 问题?
策略缺失?

第六步:最小化修复
semanage fcontext + restorecon
semanage port
setsebool -P
自定义 policy module

第七步:验证
重启服务
复现业务流程
查看 AVC 是否消失

第八步:沉淀
记录变更原因
写入部署文档
加入初始化脚本或 Ansible

18.2 临时 Permissive 验证

临时切换:

1
sudo setenforce 0

复现业务。

如果问题消失,大概率和 SELinux 有关。

验证结束后立刻恢复:

1
sudo setenforce 1

不要把临时调试变成永久裸奔。

18.3 变更记录模板

1
2
3
4
5
6
7
8
9
10
11
12
变更时间:2026-06-30
服务器:rocky-app-01
服务:order-service
问题:Nginx 无法读取 /data/order-service/public
原因:目录 SELinux 类型为 default_t
修复:
semanage fcontext -a -t httpd_sys_content_t "/data/order-service/public(/.*)?"
restorecon -Rv /data/order-service/public
验证:访问静态资源正常,无新增 AVC
回滚:
semanage fcontext -d "/data/order-service/public(/.*)?"
restorecon -Rv /data/order-service/public

第十九章:企业最佳实践

19.1 基本原则

  • 生产环境保持 Enforcing;
  • 调试用 Permissive,不用 Disabled;
  • 开启 auditd;
  • 服务使用标准目录时优先使用默认策略;
  • 使用非标准目录时配置 fcontext;
  • 使用非标准端口时配置 port context;
  • 使用服务扩展能力时优先查 Boolean;
  • 自定义策略模块必须 review;
  • 所有 SELinux 变更进入配置管理;
  • 不使用 chmod 777 掩盖问题;
  • 不使用关闭 SELinux 掩盖问题。

19.2 推荐工具链

1
2
3
4
5
6
sudo dnf install -y \
policycoreutils \
policycoreutils-python-utils \
setroubleshoot-server \
setools-console \
audit

19.3 配置管理建议

建议将以下内容纳入 Ansible / SaltStack / Shell 初始化:

  • SELinux 模式;
  • 需要安装的 SELinux 工具包;
  • 自定义 fcontext 规则;
  • 自定义 port 规则;
  • 必要 Boolean;
  • 自定义 policy module;
  • auditd 状态;
  • 关键 AVC 监控。

19.4 生产发布前检查

1
2
3
4
5
6
getenforce
sestatus
sudo semanage fcontext -l | grep company
sudo semanage port -l | grep -E '8080|8443|2222'
getsebool -a | grep httpd
sudo ausearch -m AVC -ts recent

19.5 不推荐行为

行为 问题
永久关闭 SELinux 降低安全基线
chmod -R 777 扩大传统权限风险
无脑 audit2allow 可能放大策略权限
整站目录设置可写 Web 被攻破后风险很高
容器直接 --privileged 容器隔离能力下降
忽略 audit 日志 无法定位真实原因

第二十章:常用命令速查

20.1 状态查看

1
2
3
getenforce
sestatus
id -Z

20.2 模式切换

1
2
sudo setenforce 0
sudo setenforce 1

20.3 文件上下文

1
2
3
4
5
6
ls -Z
ls -Zd /path
matchpathcon /path
sudo restorecon -Rv /path
sudo semanage fcontext -l | grep /path
sudo semanage fcontext -a -t httpd_sys_content_t "/path(/.*)?"

20.4 端口上下文

1
2
3
4
5
sudo semanage port -l
sudo semanage port -l | grep http
sudo semanage port -a -t http_port_t -p tcp 8081
sudo semanage port -m -t http_port_t -p tcp 8081
sudo semanage port -d -t http_port_t -p tcp 8081

20.5 Boolean

1
2
3
4
getsebool -a
getsebool -a | grep httpd
sudo semanage boolean -l
sudo setsebool -P httpd_can_network_connect on

20.6 日志排查

1
2
3
4
5
6
sudo ausearch -m AVC -ts recent
sudo ausearch -m AVC -ts today
sudo sealert -a /var/log/audit/audit.log
sudo grep AVC /var/log/audit/audit.log
sudo journalctl | grep -i avc
sudo dmesg | grep -i denied

20.7 策略模块

1
2
3
4
5
sudo ausearch -m AVC -ts recent --raw | audit2allow -M myapp_local
cat myapp_local.te
sudo semodule -i myapp_local.pp
sudo semodule -l | grep myapp
sudo semodule -r myapp_local

第二十一章:SELinux 企业 Checklist

21.1 初始化 Checklist

  • SELinux 状态为 Enforcing;
  • /etc/selinux/configSELINUX=enforcing
  • 安装 policycoreutils-python-utils
  • 安装并启用 auditd;
  • 可正常使用 semanage
  • 可正常使用 ausearch
  • 可正常使用 sealert
  • 自定义应用目录已规划;
  • 自定义端口已规划;
  • 容器挂载目录已规划 Label 策略。

21.2 应用上线 Checklist

  • 应用目录传统权限正确;
  • 应用目录 SELinux 标签正确;
  • 日志目录可写范围最小化;
  • 上传目录单独设置可写类型;
  • 自定义端口已配置 SELinux port context;
  • 必要 Boolean 已明确记录;
  • 无异常 AVC 日志;
  • 所有 SELinux 变更已写入发布文档。

21.3 安全审计 Checklist

  • 没有永久 Disabled;
  • 没有无脑 chmod 777
  • 没有无审查的 audit2allow 策略;
  • 没有 Web 全目录可写;
  • 没有容器无理由 --privileged
  • SELinux 变更有记录;
  • audit 日志有保留策略;
  • 关键 AVC 有监控告警。

第二十二章:FAQ

Q1:SELinux 是不是只适合安全要求很高的服务器?

不是。

SELinux 是 Rocky Linux / RHEL 系生态的重要安全能力。普通 Web 服务器、Java 应用服务器、数据库服务器、容器宿主机都应该理解和使用。

Q2:开发环境能不能关闭?

个人临时环境可以,但团队开发环境建议尽量接近生产。

否则生产上线时很容易出现:

1
开发没问题,生产 Permission denied

这句话的含金量,足以让运维和开发一起沉默。

Q3:Permissive 和 Disabled 有什么区别?

Permissive 不拦截,但仍记录日志,文件仍正常打标签。

Disabled 是完全关闭,后续再开启可能需要重新打标签。

调试建议用 Permissive,不建议 Disabled。

Q4:为什么 chmod 777 也没用?

因为 SELinux 不只看传统权限。

即使文件是 777,如果进程域没有权限访问对应 SELinux 类型,仍然会被拒绝。

Q5:为什么 chcon 不推荐长期使用?

chcon 是直接改当前文件标签,不会修改默认规则。

执行 restorecon 后,可能恢复到默认标签。

长期方案应该用:

1
2
semanage fcontext
restorecon

Q6:audit2allow 生成的规则可以直接用吗?

不建议直接用。

它只是根据拒绝日志生成允许规则,但不判断这个访问是否应该被允许。

企业环境必须 review。

Q7:容器挂载目录被 SELinux 拦截怎么办?

优先使用:

1
2
:Z
:z

例如:

1
podman run -v /data/app:/app:Z image

不要第一反应就 --privileged

Q8:SELinux 会不会影响性能?

通常不是主要性能瓶颈。

真正影响性能的常见原因更多是:

  • SQL;
  • 磁盘 IO;
  • GC;
  • 网络;
  • 锁竞争;
  • 线程池;
  • 容器资源限制。

不要把所有锅都甩给 SELinux,它已经背了太多黑锅。

参考资料

启示录

SELinux 的学习曲线确实不低。

但它最难的地方不是命令,而是思路切换:

不要问“怎么绕过它”,要问“它为什么拦我”。

当你能从 AVC denied 里读出文件标签、端口类型、进程域、Boolean 和策略边界时,SELinux 就不再是麻烦,而是系统安全的一层可解释边界。

富贵岂由人,时会高志须酬。

能成功于千载者,必以近察远。

不要轻易关闭一把你还没学会使用的锁。


SELinux 企业级入门与实战教程:不要再一键关闭 SELinux
https://allendericdalexander.github.io/2026/06/30/devops/linux/selinux_enterprise_guide/
作者
AtLuoFu
发布于
2026年6月30日
许可协议