管理 SELinux 安全性权限都给了还是拒绝原来是它在管闲事开头学 Linux 之前我一直以为权限管理就是chmod那套rwx三个字母owner / group / others 三组人把 755、644 背熟就完事了。直到这周讲 SELinux我才发现自己理解的安全有多天真。老师上课第一句就是“就算你是 root权限也不一定能访问。” 我当场就懵了——root 不是最大吗怎么还有管得住 root 的东西那节课我的脑子里全是浆糊SELinux 到底是个啥为什么文件明明是 755 权限nginx 还是给我 403还有网上教程动不动就让人先执行一句setenforce 0但没人跟我说清楚它到底干了什么、为什么重启就失效。正好上一篇博客写重置 root 密码时碰到过touch /.autorelabel当时只知道照着敲这周学完 SELinux 总算把那一串串概念串起来了。这篇就按我自己的理解顺序写一遍把上课记的那几个知识点展开成能看懂的笔记。一、先搞清楚为什么有了 chmod 还要 SELinuxDAC 和 MAC 的区别以前学的 chmod 那套权限叫自主访问控制DAC——DiscretionaryAccessControl。它有个致命问题权限由文件所有者自己说了算。只要文件属于你你想给谁读就给谁读更关键的是root 拥有一切权限绕过了所有权限检查。SELinux 用的叫强制访问控制MAC——MandatoryAccessControl。它跟 DAC 完全不同权限策略由系统统一制定不是文件所有者决定的root 也会被限制不是超级用户就能为所欲为遵循最小权限原则每个进程只给够用的权限我当时的理解DAC 是文件主人说了算MAC 是系统说了算。进程想碰资源DAC 先查一遍 rwx过了之后 SELinux 还要按策略再查一遍两道关都过才放行。所以网上的 CentOS 教程第一句就是setenforce 0其实就是嫌第二道关麻烦——但它把最关键的安全防线给关了而且很多人不知道这只是临时的。SELinux 是怎么保护的SELinux 给每个进程、文件、端口都打上一个**安全上下文security context标签。访问发生时SELinux 把进程的标签和客体的标签放进策略policy**里比对不满足策略就直接拒绝连 root 都不给面子。二、三种模式Enforcing / Permissive / Disabled对应课堂第 4 题SELinux 有三种模式这是我这周记得最牢的模式getenforce 输出行为强制模式Enforcing不符合策略就拒绝并记录日志宽容模式Permissive不拒绝只记录告警日志禁用Disabled完全不管查看当前模式getenforce# Enforcing临时切换不写配置文件重启失效setenforce0# 切到宽容模式Permissivesetenforce1# 切回强制模式Enforcing课堂第 4 题的答案setenforce 0是临时把 SELinux 切成宽容模式。它不阻止违规访问但会把告警记到日志里重启后就恢复原样。要想永久改得编辑配置文件vim/etc/selinux/configSELINUXenforcing # 可选 enforcing / permissive / disabled SELINUXTYPEtargeted # 默认策略还有 minimum 和 mls改完配置文件要重启才完全生效当前运行模式还得靠setenforce手动切。踩坑我第一次做实验时执行了setenforce 0发现挺好使就以为系统一直这样了。结果第二天开机getenforce一看又变回Enforcing了。找半天才想起老师说的临时两个字。三、安全上下文那个冒号分隔的标签这是这章最核心的概念。安全上下文就是附加在进程、文件、端口上的安全标签格式是四段冒号分隔用户:角色:类型:级别 unconfined_u:object_r:httpd_sys_content_t:s0用户SELinux 用户不是系统用户如unconfined_u、system_u角色如object_r客体、system_r系统进程类型最关键的一段如httpd_sys_content_t级别MLS/MCS 的级别一般是s0多类别时会有c0.c1023查看文件和进程的上下文ls-Z/etc/passwd# system_u:object_r:etc_t:s0 /etc/passwdps-eZ|grepsshd# system_u:system_r:sshd_t:s0-s0:c0.c1023 ...id-Z# unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023SELinux 策略就是靠比对上下文主要是类型来判断访问权限的。进程是httpd_t类型它就只能访问类型匹配的内容比如httpd_sys_content_t想碰/etc/shadowshadow_t就会被拦。我当时把这个理解成工作证对工牌进程带着工作证文件贴着工牌门卫策略只放行对得上的。四、让 httpd 能读 /custom 目录这是课堂的实操题也是 RHCSA 常见的考点把 /custom 目录设为网站内容目录让 httpd 能读。第一次我直接chmod 777 /custom心想权限都给了肯定行。结果刷新页面还是 403。看日志才知道是SELinux 拦的——/custom 目录的文件默认是default_t类型httpd 根本不让碰。正确做法分两步先定规则再打标签。第一步定义文件上下文规则semanage fcontext-a-thttpd_sys_content_t/custom(/.*)?这条命令的含义给/custom目录以及里面所有文件(/.*)?这个正则就是匹配子目录和文件定义一条规则——将来的标签类型是httpd_sys_content_t。semanage fcontext只是写规则并不会立刻改文件标签。第一次我没搞清楚这步执行完就去访问还是 403。第二步用 restorecon 按规则打标签restorecon-Rv/customrestorecon会按规则重新设置文件的上下文-R递归处理目录里所有内容-v显示过程。查看当前有哪些规则semanage fcontext-l|grepcustom查看标签是否打上ls-Zd/custom# system_u:object_r:httpd_sys_content_t:s0 /customchcon 和 restorecon 的区别除了restorecon还有个chcon能直接改标签chcon-thttpd_sys_content_t /custom/index.html但chcon改的是当前标签是临时的跟规则无关之后一次restorecon就会被打回原形。所以规范做法永远是用semanage fcontext定规则 restorecon打标签。记法semanage fcontext像立规矩restorecon像照规矩办事chcon像临时手动改。注意semanage 可能没装RHEL9 上执行semanage可能报command not found需要装个包dnfinstall-ypolicycoreutils-python-utils五、布尔值开关式策略Bonus课堂上顺带讲的我觉得挺有用。SELinux 有些策略是开关式的叫布尔值boolean比如httpd 能不能联网“能不能访问家目录”。getsebool-a|grephttpd setsebool-Phttpd_can_network_connect on踩坑setsebool如果不加-P重启后就还原了。加-P才是永久persistent。这跟setenforce 0一个套路——临时和永久的区别真的是这章最容易踩的坑。六、被拒了怎么排查遇到权限明明给了还是拒绝先别急着chmod 777先看是不是 SELinux 拦的。SELinux 的拒绝记录在审计日志里# 最近被拒绝的记录ausearch-mavc-tsrecent# 直接 grep 日志grepdenied/var/log/audit/audit.log装了 setroubleshoot-server 的话还能让它直接给建议dnfinstall-ysetroubleshoot-server sealert-a/var/log/audit/audit.logsealert会给出类似你想让 httpd 访问某个目录可以执行semanage fcontext ...的建议对新手特别友好。我踩过的坑合集考前必看坑说明解决方法只chmod 777不看 SELinux权限给了还是 403先查 audit.log八成是 SELinux 拦的setenforce 0重启失效以为永久生效永久要改/etc/selinux/configsemanage命令不存在提示 command not founddnf install policycoreutils-python-utils只写了规则忘了 restorecon执行semanage fcontext后直接访问restorecon -Rv按规则打标签restorecon忘了-R只改了目录本身子文件没变加-R递归mv 过来的文件还是 403mv 保留原来的上下文用restorecon重新打标签setsebool忘加-P重启后开关还原永久要加-P把 SELINUX 改成 disabled想改回 enforcing 后登录不了/卡住改回 enforcing 重启等它自动 autorelabel 扫完关于mv 还是 403cp出来的新文件会继承目标目录的默认上下文但mv是移动文件的标签原封不动跟着走。所以把一个 html 从/homeuser_home_tmv 到/var/www/html标签还是user_home_thttpd 照样读不了——必须restorecon一下。这是我猜了半天才发现的。