☰
RH134 SELinux实战笔记:从安全上下文到AVC排错精讲
2026/9/29 18:50:41 网站建设 项目流程

昨晚我照着文档在RHEL 9上部署一个内部Web服务,firewall-cmd已经放行了端口,目录权限也改成了755,curl却一直返回403。折腾一个多小时,最后用ausearch -m AVC翻审计日志才发现,是SELinux把httpd进程的文件访问拦了下来。这种经历,凡是学过RH134的朋友应该都不陌生。

RH134作为Red Hat系统管理进阶课程,SELinux单独成章,篇幅不多,但绝对值得反复咀嚼。它不要求你成为一名安全策略编写专家,却要求你掌握一套完整的"观察—分析—修复"思路:模式怎么切换、安全上下文是什么、布尔值在哪查、日志去哪看。这篇文章是我学习这一章的完整笔记,从权限模型到实操命令,再到两个真实排错链路,适合正在备考RH134的学员,也适合被"SELinux导致服务异常"坑过的运维同行。

1. 从DAC到MAC:为什么root说了不算

SELinux刚接触时,最颠覆认知的一点是:root用户居然也会被拒绝。很多人在普通Linux环境里习惯了"root万能",于是遇到SELinux拦截时第一反应是"系统出bug了",接着就是"关掉它"。要真正理解SELinux,得先搞明白它到底补上了传统权限模型的哪个漏洞。

1.1 传统rwx权限管不住root

传统Linux权限模型叫DAC(自主访问控制),每个文件都标着所有者、所属组、其他人三组rwx权限,逻辑上完全由"文件所有者"来决定谁能访问这个文件。这套机制用了几十年,问题在于:如果进程是以root身份运行的,DAC对它来说基本是透明的。

试想一个场景:Apache的httpd进程以root启动,通过漏洞被攻击者拿到Shell,攻击者直接读取/etc/shadow、把自己写进/root/.ssh/authorized_keys,DAC完全拦不住,因为root可以无视文件权限位直接读改。即便严格遵循最小权限原则给进程降权,也做不到"进程A能读文件X但不能读文件Y"这种细粒度隔离。DAC的决策依据只有"对象属于谁、进程属于谁",没有"进程本身的身份和行为是否可信"。

这还不够。传统权限还面临setuid程序、共享库注入等利用方式,一旦进程权限提升,攻击面直接扩散到整个文件系统。RH134课程里讲SELinux之前,会花一定篇幅强调这份风险——不是为了否定DAC,而是为了说明仅仅依赖文件权限的服务部署,在安全上存在多大的盲区。

1.2 SELinux引入的MAC:策略优先于身份

SELinux实现的是MAC(强制访问控制)。它的核心思想是:文件系统上每个对象、系统里每个进程,都被打上一个叫做"安全上下文"的标签;系统管理员通过策略文件统一规定"哪些标签的进程可以访问哪些标签的对象"。注意,这个判断发生在DAC判断之后,即使DAC放行了,MAC不匹配照样拒绝。

可以这样类比DAC和MAC的区别:DAC相当于办公室门口的签到本,只要你是这个公司的人(用户身份匹配)就能进;MAC相当于每间机房的独立门禁卡,即便你有公司工牌,门禁系统没有授予你进入机房A的权限,你一样进不去。root在公司里相当于持有万能钥匙,但在MAC的规则里,万能钥匙只对应很少的区域,其他区域看的是卡上的权限标签。

SELinux里进程的安全上下文像一个"domain(域)",文件的安全上下文则是"type(类型)"。HTTP服务进程跑在httpd_t域,普通网站文件标记为httpd_sys_content_t,策略中定义了httpd_t可以对httpd_sys_content_t进行读取,于是正常访问被放行。但如果你把网站目录改成/data/web,这个目录的默认标签可能是usr_t,策略中没有httpd_t读取usr_t的规则,于是一切变得"诡异":权限、端口、防火墙都没问题,服务就是不可达。

1.3 RH134为何把SELinux设为独立章节

RH134的定位是"系统管理员进阶",服务部署是重头戏——Apache、NFS、Samba、vsftpd一个接一个。这些服务哪个都绕不开SELinux策略:改默认配置、换目录、调端口、跨网络共享,每一样都有可能触发拦截。更关键的是,RH134考试环境评分时会检查你有没有保留SELinux的强制模式,直接把SELinux禁用后部署服务,也许本机能跑,但生产环境不会允许你这么做。

所以这一章的教学目标非常明确:不要求你写出复杂的.te策略文件,但要求你熟练使用semanage、setsebool、restorecon、ausearch这套组合拳,知道出了问题时去哪找线索,而不是先想到关SELinux。这套能力,恰恰是很多自学Linux的人最缺的。

2. 三种模式切换背后的风险,都藏在重启里

SELinux有三种运行模式:enforcing(强制)、permissive(宽容)、disabled(禁用)。很多人理解成"开、半开、关",这没错,但实际操作中,模式的切换远没有听起来那么简单,尤其在disabled和enforcing之间来回切,重启一次可能让整个系统起不来。

2.1 三种模式的区别不是"关不关"这么简单

用一张表快速看清差别:

模式策略是否生效是否记录日志典型适用场景
enforcing是,违反策略直接拒绝是,写入audit.log生产环境、考试环境
permissive否,违反策略放行是,写入audit.log调试策略、观测影响范围
disabled否否长期不需要SELinux,如部分容器镜像

临时切换用setenforce 0(切到permissive)和setenforce 1(切回enforcing),这条命令只影响当前运行状态,重启后失效,想永久改变要修改/etc/selinux/config文件。

一个常见误区是:需要"关闭SELinux"时直接setenforce 0,心想重启后还是关的。其实重启后系统还会按config文件里写的模式启动。想要彻底禁用,得把SELINUX=disabled写进配置文件,还要重启。反过来说,如果你只是想让一个服务暂时通过验证,用setenforce 0就够了,别动不动改配置文件,改完忘了改回来,生产环境会出大事故。

2.2 从disabled切回enforcing,最容易翻车

这是我在练习中踩过的最深一坑。某次实验环境因需求把SELinux设成了disabled,跑了几天,再改回enforcing重启,发现系统启动卡在奇怪的地方,登录后各种服务异常,网络管理也报错。

原因在于:SELinux disabled状态下,系统不会维护任何文件的安全上下文。期间新建、改动过的文件都没有正确标签,甚至关键系统文件在重启时应该被赋予的类型也被跳过。当你重新开启enforcing时,内核开始用活动策略检查所有对象,发现大量文件的标签缺失或错误,于是表现为"系统突然什么都不正常"。

正确做法是在切换前让系统重建标签:修改配置为SELINUX=enforcing后,在根目录创建自动relabel标记文件,然后重启:

touch /.autorelabel reboot

系统启动时检测到/.autorelabel,会对整个文件系统重新打上符合当前策略的标签。完成后该文件自动消失。注意,这个过程在文件较多时耗时很长,务必预留停机时间,千万别中途断电。

2.3 日常运维的查看三板斧

判断当前状态,三个命令最常用:

getenforce # 输出 Enforcing / Permissive / Disabled sestatus # 显示模式、策略版本、加载的策略名 sestatus -v # 额外显示关键进程和文件的安全上下文

我在排查服务问题时,习惯把sestatus和ps -eZ、ls -Z配合使用,先确认系统整体处于什么模式,再看目标进程和文件分别是什么标签。如果进程的domain是unconfined_t,说明它不受SELinux限制,问题多半不在SELinux;如果domain很明确(比如httpd_t),那就需要顺着AVC日志往下查了。

3. 安全上下文:拦你的那串奇怪的字符串

在支持SELinux的目录里执行ls -Z,你会看到每个文件额外多出一段类似system_u:object_r:httpd_sys_content_t:s0的内容。这串字符就是安全上下文,SELinux一切判断都基于它。学这一节的关键是理解三段分别代表什么,以及哪些字符串需要你关注。

3.1 user、role、type各自管什么

安全上下文格式是user:role:type,在某些发行版还会带level(如s0,用于多级安全策略,RH134一般只需要了解)。

  • user是SELinux用户,跟系统登录用户不是一回事。它更像一个"策略身份",比如system_u代表系统进程和服务,unconfined_u代表不受约束的用户。我们平时管理文件时基本不需要改它。
  • role用于角色切换,文件对象上基本都是object_r,进程可能有system_r等。管理员日常也不需要动它。
  • type(也叫类型)才是核心。文件上叫"类型",进程上叫"domain",两者都是策略判断的主要依据。

RH134并不要求深入理解SELinux用户映射,但要求你能读懂type,并且知道某个服务的进程domain是什么、对应的文件type应该是什么。比如httpd进程的domain是httpd_t,网页文件通常是httpd_sys_content_t,SELinux的策略允许httpd_t访问这类文件。

3.2 类型强制:为什么换了目录就不行

SELinux默认策略是"目标策略"(targeted),核心机制就是类型强制。可以这样理解:每个服务像一个持卡的员工,卡上写着他的权限等级(domain);每个文件桌上贴着权限标签(type);保安(SELinux策略)手里有一份对照表,只有"domain + type"在表上出现了,才能放行。

默认情况下,/var/www/html目录里的文件被打上httpd_sys_content_t,所以httpd读起来没问题。你换到/data/web,新建文件通常被打成usr_t,对照表里没有httpd_t读取usr_t的规则,于是403。这不是文件权限问题,而是SELinux认为这个进程不"应该"访问这些文件。

这恰恰是SELinux的精髓:让服务默认只能访问它"该访问"的东西。管理员需要做的不是关掉门禁,而是正确告知系统"这个目录现在是网站目录,请按网站目录的类型处理"。

3.3 查看标签的三个命令

ls -Z /var/www/html/index.html ps -eZ | grep httpd id -Z

id -Z显示当前用户的SELinux身份,ls -Z看文件类型,ps -eZ看进程domain。图形文件管理器在RHEL上右键属性也能看到安全上下文,但命令行更快。

3.4 修改标签:chcon、restorecon、semanage

可以把类型改掉,但方式决定持久性:

chcon -t httpd_sys_content_t /data/web/index.html

chcon直接修改对象的安全上下文,立刻生效,适合临时验证。但它不改变策略规则,一旦日后对该目录执行restorecon,标签又会恢复到策略默认值。

semanage fcontext -a -t httpd_sys_content_t '/data/web(/.*)?' restorecon -Rv /data/web

semanage fcontext才是把规则写入策略库存的办法。它告诉SELinux"以后这个路径下创建的文件,默认使用指定类型"。restorecon按照策略库里的映射关系,把现有文件的标签修正过来。这组合才是生产环境的标准操作。

为什么推荐semanage而不是chcon?因为restorecon是一个会被反复使用的修复命令,比如系统升级、管理员误操作后都需要用它恢复。如果当初只用了chcon,没有写进策略库,执行restorecon后标签就丢失了。用semanage注册规则,等于给了系统一个长期记忆。

3.5 一个典型的目录迁移案例

把网站从/var/www/html迁到/opt/web,常规操作是改httpd.conf的DocumentRoot,然后复制文件、放开权限。但在enforcing模式下,还需要两步:

semanage fcontext -a -t httpd_sys_content_t '/opt/web(/.*)?' restorecon -Rv /opt/web

如果网站还要写入文件,比如上传目录,还需要加上可写类型:

semanage fcontext -a -t httpd_sys_content_rw_t '/opt/web/upload(/.*)?' restorecon -Rv /opt/web/upload

一不注意就会少一步。我的习惯是迁移任何服务目录后,第一件事就是semanage fcontext注册新路径,而不是等到访问报错再排查。

4. 排错链路:从服务异常到策略修改

SELinux排错最怕的是"用错误的方式做对了的事"。比如遇到httpd访问不了,直接setenforce 0确实能临时解决,但下次重启又复发,而且问题可能不止一处。正确的链路是:确认模式 → 复现问题 → 查AVC日志 → 分析被拒原因 → 修改布尔值/端口/文件上下文 → 验证。

4.1 日志在哪里看:AVC记录

SELinux拒绝访问时,会在审计日志中写入一条AVC(Access Vector Cache)记录。主要查看入口:

ausearch -m AVC -ts recent ausearch -m AVC -p 12345 # 按PID过滤 grep "denied" /var/log/audit/audit.log sealert -l "完整日志消息"

ausearch会输出类似这样的内容:

type=AVC msg=audit(1690000000.123:456): avc: denied { read } for pid=7890 comm="httpd" name="index.html" dev="dm-0" ino=12345 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:usr_t:s0 tclass=file permissive=0

看两个关键字段:scontext是进程的domain,tcontext是目标文件的type,tclass是对象类别。上面这条日志可以直接读出:httpd_t域进程想读取类型为usr_t的文件,被拒绝。

需要说明的是,RHEL默认配置下AVC日志会进入/var/log/audit/audit.log,但如果不确定系统是否开了auditd,也可以直接看/var/log/messages或执行dmesg | grep -i selinux,信息可能少一些但同样有价值。

4.2 案例一:httpd访问不了NFS共享目录

有次NFS挂载了一个共享目录/mnt/share,Apache文档根目录指向其中,浏览器始终403,ls -l看权限没问题,NFS挂载参数也正常。

查AVC日志:

ausearch -m AVC -ts recent

结果里出现了httpd_t对nfs_t类型目录的read被拒。原因很清楚:SELinux默认不允许httpd去访问NFS文件系统类型。

修复需要打开对应布尔值:

getsebool -a | grep httpd setsebool -P httpd_use_nfs on

setsebool就是SELinux的开关总闸。布尔值数量很多,用grep过滤关键词是最高效的办法。-P参数代表持久化到磁盘,不加的话重启失效。

4.3 案例二:修改SSH端口后连接被拒

把sshd监听端口从22改到2222,放行防火墙后,客户端连接却被拒绝。这通常是SELinux对端口的强制:sshd进程只能监听被标记为ssh_port_t的端口。

可以用semanage port -l | grep ssh看到当前允许的端口列表,修改命令:

semanage port -a -t ssh_port_t -p tcp 2222

然后确认:

semanage port -l | grep ssh_port_t

类似的问题还有NFS、DNS等自定义端口,原则一模一样:服务启动失败或端口连不上时,先看AVC日志,再查semanage port -l是否包含该端口。

4.4 案例三:Samba共享目录无法写入

Samba目录默认标签是samba_share_t,如果管理员把共享目录建在/home/share,或者给已有目录打了错误的标签,客户端只能读不能写,甚至根本看不见。

semanage fcontext -a -t samba_share_t '/home/share(/.*)?' restorecon -Rv /home/share

同时注意Samba相关的布尔值,比如samba_export_all_rw用来允许Samba导出所有可读写文件系统。这类问题在RH134实验里出现频率很高,考试也喜欢用"服务配置正确但功能异常"来考察排错能力。

4.5 布尔值调整的最佳实践

SELinux布尔值的调整要遵循"最小化"原则,只开需要的开关,不要图省事全开:

getsebool -a | grep ftp setsebool -P ftpd_full_access on # 慎重,这相当于放开整个FTP域限制

练习环境下可以临时不开-P,先用当前会话验证,确认业务正常后再决定是否持久化。开启后一定要检查/var/log/audit/audit.log有没有继续输出新的AVC记录,避免"解决了A问题又触发B问题"。

5. 那些坑、考试要点和延伸思考

学SELinux最大的障碍不是概念多难懂,而是习惯性地用传统权限思维去猜问题。整理几个我在RH134学习和实际运维中反复踩过的坑,以及这门课在考试和后续技术栈里的连接点。

5.1 四个最容易踩的坑

第一,一遇到权限问题就setenforce 0。临时降级定位问题本身没问题,但很多人定位完忘了切回来,服务正常了就以为万事大吉,下次重启策略恢复后问题复发,又重复降级。生产环境如果只能在enforcing模式下运转,通过降级来"绕过"问题的习惯迟早要出事。

第二,只改/etc/selinux/config不重启,以为立即生效。这个文件只在启动阶段读取,你想让它立刻生效又不想重启,可以用setenforce 0/1临时切换,或者干脆按计划窗口重启。很多人改了配置文件后对着getenforce看了半天,觉得"怎么没变",原因就在这里。

第三,把chcon当成永久修改。前面已经说过,chcon直接改标签,一旦restorecon就会按策略库重写。正确做法是semanage fcontext注册规则,然后用restorecon落地。

第四,只关注文件权限,不关注目录权限和父目录上下文。SELinux对目录的type要求经常被漏掉,比如httpd要访问/data/web/pic,你只给pic打了httpd_sys_content_t,但父目录/data/web还是usr_t,进程在遍历路径时一样会被拦。用restorecon -Rv把整棵目录树都校正过,才不容易漏。

5.2 RH134考试里SELinux的考查方式

RH134考试不会让你去写策略文件,它的重点是通过一系列服务配置场景,暗中检查你是否掌握了SELinux管理。比如把网站根目录换到一个新路径,要求排错直到服务能正常访问;或者把sshd端口修改后要求服务依然可用;又或者Samba共享能在客户端读写。

这些题目的共同点是:如果直接关闭SELinux,服务可能判定成功,但考试环境会检查SELinux模式,禁用了或者长期permissive都可能导致整题零分。备考时建议在enforcing模式下完成所有服务实验,并且练熟下面的组合:

semanage fcontext -a -t 类型 '路径(/.*)?' restorecon -Rv 路径 semanage port -a -t 服务类型 -p tcp 端口 setsebool -P 布尔值 on ausearch -m AVC -ts recent

练到看到"服务异常"第一反应是去查AVC日志,而不是去看防火墙和权限,基本就过关了。

5.3 延伸:SELinux不仅是红帽课程里的知识点

SELinux并不只是RHEL的专属概念。Android内核也默认开启了SELinux强制模式,把每个应用当成一个独立domain,限制应用访问系统属性、传感器、其他应用的数据。近期有开发者反馈,Android 16上某些原本可用的数据存储方案(比如SharedPreferences的兼容实现)因SELinux策略收紧而无法工作,底层原因本质上就是"目标对象的标签或domain的权限不再匹配"。理解了RH134里的domain与type的概念,再看这类移动端问题会通透很多:这不是Flutter、Java代码能解决的问题,而是安全策略层面的限制。

学习RH134这一章真正的收获,是建立"系统安全状态需要被观测和管理"的意识。它不是给你一套需要背的规则,而是给你一套定位问题和修正状态的工具箱。把这套工具练熟,无论以后管理服务器还是排查应用兼容性问题,都会比别人多一个维度。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询