一、SELinux 基础认知:先搞懂 "是什么"
这部分解决 "SELinux 的定位与核心价值",帮学员建立 "为什么需要 SELinux" 的宏观认知,避免一开始被技术细节劝退。
1. SELinux 的定义与核心价值
-
定义 :SELinux(Security-Enhanced Linux,安全增强型 Linux)是集成到 Linux 内核中的强制访问控制(MAC)安全机制,通过预先定义的 "策略规则" 限制进程(主体)对文件、端口等资源(客体)的访问,即使进程拥有 root 权限,也只能执行被允许的操作。
-
核心价值:
-
解决 "传统权限(DAC)的缺陷":传统 Linux 权限(读 / 写 / 执行、用户 / 组 / 其他)是 "自主访问控制",root 用户拥有无限权限,一旦进程被劫持(如黑客入侵 Web 服务),攻击者可利用 root 权限肆意破坏;SELinux 是 "强制访问控制",即使是 root 进程,超出规则的操作也会被禁止。
-
最小权限原则:为每个进程分配 "刚好够用" 的权限(如 httpd 进程只能访问 Web 目录和 80 端口,无法读写
/etc/passwd),限制攻击面。 -
合规性要求:满足金融、医疗等行业的安全合规标准(如 PCI DSS),必须启用强制访问控制机制。
-
2. SELinux 与传统 Linux 权限(DAC)的区别(关键对比)
学员最易混淆 "SELinux 权限" 和 "rwx 权限",需用表格明确边界:
| 对比维度 | 传统 Linux 权限(DAC,自主访问控制) | SELinux(MAC,强制访问控制) | 核心差异点 |
|---|---|---|---|
| 控制逻辑 | 基于 "用户 / 组" 判断:"谁(用户)能对资源做什么" | 基于 "策略规则" 判断:"哪个进程(主体)能对哪个资源(客体)做什么" | 控制对象:用户 vs 进程 + 资源 |
| 权限主体 | 用户(如 root) | 进程(如 httpd、sshd) | 主体:用户身份 vs 进程身份 |
| 最高权限 | root 用户拥有 "无限权限"(可绕过所有 DAC 限制) | 即使是 root 进程,也受 SELinux 规则限制(无法绕过) | 权限边界:root 无敌 vs 规则至上 |
| 典型场景 | 日常文件访问控制(如 chmod 755 file) |
限制服务进程的 "越权行为" (如防止 httpd 读写 /root 目录) |
用途:基础访问 vs 安全防护 |
Red Hat 官方明确了 SELinux 访问控制的两步判定流程,核心内容翻译与提炼如下:
第一步:Linux 原生 DAC 检查 "SELinux 并非替代 Linux 传统的自主访问控制(DAC),而是在其基础上增加强制访问控制(MAC)。当一个进程(主体)尝试访问一个文件或资源(客体)时,内核会首先执行 DAC 检查 ------ 即校验文件的所有者、组、其他用户的 rwx 权限(如
chmod配置的权限)。若 DAC 检查失败(例如,普通用户尝试修改 root 所有的只读文件),内核会直接返回EACCES(权限拒绝)错误,且不会触发后续的 SELinux MAC 检查。"第二步:SELinux MAC 检查 "仅当 DAC 检查通过后,SELinux 安全模块才会介入,执行 MAC 检查。此时,SELinux 会提取主体的安全上下文(如进程的
httpd_t类型)和客体的安全上下文(如文件的httpd_sys_content_t类型),并根据预定义的 SELinux 策略规则(如 "允许httpd_t读取httpd_sys_content_t类型的文件")判断是否允许访问。若 MAC 检查失败,内核会返回 SELinux 相关的权限拒绝(通常记录为 AVC 日志);若通过,则允许访问最终完成。"
二、SELinux 核心原理:搞懂 "怎么工作"
这是 SELinux 的技术核心,需讲清 "访问控制的底层逻辑",重点突破 "安全上下文" 和 "策略规则" 两个核心概念。
1. SELinux 的基本模型:主体、客体、策略、安全上下文
SELinux 的访问控制基于 "主体(Subject)→ 客体(Object)→ 策略规则(Policy)" 的三元模型,核心是通过 "安全上下文" 标识主体和客体的 "身份",再通过策略规则判断是否允许访问。
-
主体(Subject):指 "正在运行的进程"(如 httpd、sshd 进程),每个进程都有 SELinux 安全上下文。
-
客体(Object):指 "被访问的资源"(如文件、目录、端口、设备等),每个客体也有 SELinux 安全上下文。
-
策略(Policy):预定义的 "规则集合",规定 "哪些主体(进程)可以访问哪些客体(资源)",是 SELinux 的 "大脑"。
-
安全上下文(Security Context) :SELinux 给主体和客体打上的 "身份标签",格式为
user:role:type:level(前三者是核心,level 用于 MLS 策略),访问控制的核心是 "比较主体和客体的安全上下文是否匹配策略规则"。
2. 安全上下文:SELinux 的 "身份标签"(核心中的核心)
安全上下文是 SELinux 最抽象也最关键的概念,需拆解结构并结合实例讲解:
(1)安全上下文的组成(以 unconfined_u:object_r:httpd_sys_content_t:s0 为例)
| 字段 | 含义 | 核心作用 | 示例(httpd 相关) |
|---|---|---|---|
user(用户) |
SELinux 用户(非 Linux 系统用户),标识 "访问者类型" | 区分不同类型的访问主体(如系统进程、用户进程) | unconfined_u(不受限用户,如 root 进程)、system_u(系统进程) |
role(角色) |
SELinux 角色,关联 "用户可执行的操作" | 限制用户 / 进程的 "职责范围"(如系统角色、用户角色) | object_r(客体角色,用于文件 / 资源)、system_r(系统进程角色) |
type(类型) |
最核心的字段,主体的 type 称为 "域(domain)",客体的 type 称为 "类型" | 策略规则主要基于 type 定义(如 httpd_t 进程能否访问 httpd_sys_content_t 文件) |
主体 type:httpd_t(httpd 进程的域);客体 type:httpd_sys_content_t(Web 目录的类型) |
level(级别) |
用于 MLS(多级安全)策略,标识资源的 "敏感程度"(如 s0、s1:c0.c1023) |
实现 "高敏感资源只能被高权限进程访问" | 仅在 MLS 策略中生效,默认 targeted 策略不常用 |
主体(进程)能否访问客体(文件 / 端口等资源),取决于 "主体的 type" 与 "客体的 type" 之间是否存在允许访问的规则(allow 规则)。
httpd 进程的 SELinux 类型是
httpd_t(主体 type),Web 目录/var/www/html的类型是httpd_sys_content_t(客体 type)。SELinux 策略中预定义了规则:
allow httpd_t httpd_sys_content_t:file read;(允许 httpd 进程读取 Web 目录的文件)。若将
/var/www/html的类型改为etc_t(/etc目录的类型),则 httpd 进程访问该目录时,SELinux 会拒绝(因为策略中没有allow httpd_t etc_t:file read;规则),即使 Linux 权限是777也无法访问。
/etc/selinux/targeted/contexts/users/目录下的guest_u、root、staff_u等文件,对应的是SELinux 用户(SELinux User) ------ 这是 SELinux 安全模型中用于身份标识的抽象概念,与 Linux 系统用户(如 /etc/passwd 中的用户)并非直接对应,而是通过映射关系关联(如 Linux 的 root 用户默认映射到 SELinux 的 root 用户)
查映射:用 semanage login -l 看 Linux 用户对应哪个 SELINUX 用户;
角色(system_r、unconfined_r 等)的作用是 "限制用户可切换的 type 范围",但不直接决定进程能否访问资源。
[root@rhce ~]# semanage login -l
Login Name SELinux User MLS/MCS Range Service
__default__ unconfined_u s0-s0:c0.c1023 *
root unconfined_u s0-s0:c0.c1023 *
[root@rhce ~]#
系统可以把LINUX用户识别成以下七种
│ ├── users
│ │ ├── guest_u
│ │ ├── root
│ │ ├── staff_u
│ │ ├── sysadm_u
│ │ ├── unconfined_u
│ │ ├── user_u
│ │ └── xguest_u
[root@rhce ~]# cat /etc/selinux/targeted/contexts/users/root
system_r:crond_t:s0 unconfined_r:unconfined_t:s0 sysadm_r:cronjob_t:s0 staff_r:cronjob_t:s0 user_r:cronjob_t:s0
“当进程处于 system_r:crond_t:s0 这个初始上下文时,允许它转换到后面列出的目标上下文(即切换到新的 role 和 type)”。
例如:crond_t 进程(定时任务进程)可以转换为 unconfined_t(无限制类型)或 cronjob_t(cron 任务专用类型),转换后以新的 type 运行
一、各 SELinux 用户的用途(典型场景)
每个 SELinux 用户文件定义了该用户在不同场景下的安全上下文转换规则,其核心作用是限制该用户能使用的角色和权限范围,具体如下:
SELinux 用户 对应文件 典型用途 权限等级 rootroot对应 Linux 系统的 root管理员,是 SELinux 中权限最高的用户,可切换到几乎所有角色(如sysadm_r、unconfined_r),用于系统核心管理操作。最高(可执行敏感操作,如修改系统配置、管理服务) unconfined_uunconfined_u对应 Linux 中 "无限制用户"(如普通用户但需较高权限),默认关联 unconfined_r(无限制角色),权限接近root但受部分限制,适合信任的普通用户。高(允许大部分操作,无需严格遵循 SELinux 类型限制) sysadm_usysadm_u系统管理员专用 SELinux 用户,关联 sysadm_r(系统管理员角色),权限聚焦于系统管理(如启停服务、管理用户),但比root更受限(避免无差别高权限)。中高(仅允许系统管理相关操作) staff_ustaff_u对应 "Staff 角色用户"(如中级运维人员),关联 staff_r角色,权限介于管理员和普通用户之间,可执行部分管理操作(如su提权)但受严格限制。中等(有限的管理权限,核心操作需授权) user_uuser_u普通受限用户,关联 user_r角色,权限仅限于个人操作(如访问家目录、使用普通应用),无法执行系统管理操作,适合一般用户。低(仅允许个人级操作) guest_uguest_u临时访客用户,权限极低,仅允许最基础的操作(如浏览网页、读取公共文件),无法修改系统或个人配置,适合临时登录场景。 极低(严格限制,防止任何敏感操作) xguest_uxguest_u图形界面下的访客用户,专为图形登录设计,权限与 guest_u类似,但额外限制图形界面相关操作(如禁止修改桌面配置),适合公共电脑的临时使用。极低(图形场景的访客权限) 二、SELinux 用户与角色(Role)的区别
SELinux 中,"用户" 和 "角色" 是两个不同层级的安全概念,核心区别体现在 "范围" 和 "关联关系" 上:
维度 SELinux 用户(User) SELinux 角色(Role) 定义 抽象的身份标识,代表 "谁在操作"(如 root、user_u)。操作权限的 "角色定位",代表 "扮演什么角色"(如 sysadm_r、user_r)。核心作用 限制 "允许使用的角色范围"(一个用户可关联多个角色,但不能超出其允许的范围)。 限制 "允许访问的类型(Type)范围"(一个角色关联多个类型,类型决定实际访问权限)。 层级关系 上层概念,是角色的 "容器":用户 → 允许的角色 → 允许的类型。 中层概念,连接用户和类型:角色是用户与类型之间的桥梁。 举例 staff_u(SELinux 用户)允许使用staff_r、user_r等角色,但不能使用sysadm_r(除非授权)。staff_r(角色)允许访问staff_t、user_t等类型,但不能访问sysadm_t(管理员专用类型)。与 Linux 用户的关联 Linux 用户需通过 /etc/selinux/targeted/logins等文件映射到 SELinux 用户(如 Linux 的root映射到 SELinux 的root)。角色不直接与 Linux 用户关联,而是通过 SELinux 用户间接关联(用户→角色→类型)。 三、总结
SELinux 用户是 "身份标签",决定了用户能 "扮演哪些角色";
角色是 "权限标签",决定了能 "访问哪些类型的资源";
两者通过 "用户→角色→类型" 的层级关系,共同实现 SELinux 的 "最小权限控制":用户只能通过允许的角色,访问该角色允许的类型资源,避免权限滥用。
日常运维中,无需直接修改这些用户文件,而是通过
semanage login命令管理 Linux 用户与 SELinux 用户的映射(如为普通 Linux 用户分配staff_u),从而间接控制其权限范围。
3. SELinux 策略:规则的集合("允许 / 拒绝" 的依据)
策略是 SELinux 的 "规则手册",需讲清策略的类型、组成和作用:
(1)常见策略类型(RHEL 默认预装)
| 策略类型 | 适用场景 | 特点(教学重点) |
|---|---|---|
targeted |
默认策略,仅对 "网络服务进程"(如 httpd、sshd、mysql)进行严格限制,对普通用户进程限制较少 | 兼顾安全与易用性,适合生产环境(99% 场景用此策略) |
minimum |
在 targeted 基础上,仅限制 "最关键的服务"(如 sshd),限制范围更小 | 适合对性能要求高、安全需求低的场景 |
mls |
多级安全策略,基于 "安全级别(level)" 控制访问(如绝密文件只能被最高级进程访问) | 安全级别极高,适合军事、涉密场景,配置复杂 |
rhel9中SELinux默认的策略是targeted,如果要使用其他策略需要额外俺装相应的策略包:selinux-policy-minimum、selinux-policy-mls
/etc/selinux/ 目录的核心逻辑是 "分层存储、按需加载":
-
顶层文件(
config、semanage.conf)控制全局模式; -
targeted目录按 "策略开关 - 上下文映射 - 核心策略" 拆分配置,其中contexts/files是文件权限的关键,policy/policy.33是访问规则的本体; -
二进制文件(如
.bin、policy.33)用于 SELinux 高效加载,文本文件(如file_contexts、file_contexts.local)用于用户配置修改。
日常运维中,修改最多的是 config(启用 / 禁用 SELinux)、file_contexts.local(自定义文件上下文),以及通过 semanage 命令间接修改 logins、seusers 等映射文件。
[root@rhce ~]# grep /usr/share/nginx /etc/selinux/targeted/contexts/files/file_contexts
/usr/share/nginx/html(/.*)? system_u:object_r:httpd_sys_content_t:s0
一、顶层核心文件(/etc/selinux/ 目录下)
这两个文件是 SELinux 的 "全局控制入口",决定 SELinux 的整体运行模式和管理规则。
文件名 作用说明 configSELinux 主配置文件,控制 SELinux 的启用状态 和策略类型 ,关键配置项包括:- SELINUX:取值enforcing(强制模式)、permissive(宽容模式)、disabled(禁用);-SELINUXTYPE:取值targeted(默认,仅对关键服务生效)、mls(多级安全模式,更严格)。semanage.confsemanage命令(SELinux 策略管理工具)的配置文件,定义semanage的默认行为,如:- 策略模块的存储路径;- 是否启用审计日志;- 默认的策略类型(与config中SELINUXTYPE对应)。二、targeted 子目录(/etc/selinux/targeted/)
targeted是 RHEL 9 默认的 SELinux 策略类型(对应config中SELINUXTYPE=targeted),该目录存储 targeted 策略的所有具体配置和数据,是 SELinux 策略的核心存储区。1. 策略开关与映射文件(targeted 目录下直接文件)
文件名 作用说明 booleans.subs_distSELinux 布尔值(开关)的 "分发版默认映射" 文件,定义系统预装布尔值的默认名称和关联规则,用户一般无需修改(自定义布尔值需通过 semanage boolean命令)。loginsSELinux 用户与 Linux 系统登录账号的映射配置文件,记录 "哪个 Linux 账号对应哪个 SELinux 用户"(如 root对应rootSELinux 用户,普通用户默认对应unconfined_u)。setrans.confSELinux 翻译服务(setrans)的配置文件,用于将 SELinux 安全上下文(如 unconfined_u:unconfined_r:unconfined_t:s0)转换为人类易读的格式,主要用于日志显示和用户交互。seusers与 logins功能类似,是 SELinux 用户与 Linux 账号的兼容映射文件 ,优先级低于logins,主要用于兼容旧版本 SELinux 配置(现代系统优先读取logins)。2. contexts 子目录(/etc/selinux/targeted/contexts/)
存储 SELinux 安全上下文的映射规则,定义 "不同资源(文件、进程、端口、用户)应具备的安全上下文",是 SELinux 访问控制的核心依据。
子文件 / 子目录 作用说明 customizable_types定义 "可自定义安全类型" 的列表,即哪些 SELinux 类型(如 httpd_sys_content_t)允许用户通过chcon或semanage fcontext命令修改,避免用户误改系统关键类型。dbus_contexts为 D-Bus 服务(Linux 桌面 / 系统的进程通信机制)定义安全上下文规则,确保 D-Bus 进程间的通信符合 SELinux 策略,防止未授权进程通过 D-Bus 访问敏感服务。 default_contexts定义 "默认安全上下文",包括用户登录时的默认上下文(如 unconfined_u:unconfined_r:unconfined_t:s0)、进程启动时的默认上下文,是 SELinux 上下文的 "基础模板"。default_type指定系统默认的 SELinux 类型( default_t),用于 "未明确匹配其他上下文规则" 的资源(如临时文件、未知路径的文件),避免资源因无上下文而被 SELinux 直接拦截。failsafe_context"故障安全" 上下文,当 SELinux 无法获取资源的正常上下文时(如配置错误、文件损坏),临时使用该上下文,确保系统不会因上下文缺失而完全无法运行。 files子目录文件安全上下文的核心配置目录,详见下方 "files 子目录详解"。 initrc_context为系统初始化进程(init 或 systemd 启动阶段的进程)定义默认安全上下文,确保初始化过程中进程的访问权限符合 SELinux 策略。 lxc_contexts为 LXC(Linux 容器)相关进程和资源定义安全上下文,限制容器内进程对宿主机的访问,实现容器与宿主机的 SELinux 隔离。 openssh_contexts为 OpenSSH 服务(ssh 进程、sshd 守护进程)定义安全上下文规则,确保 SSH 服务的访问(如密钥文件读取、端口绑定)符合 SELinux 策略。 removable_context为可移动存储设备(U 盘、移动硬盘)定义默认安全上下文,防止外部存储中的恶意文件通过 SELinux 权限漏洞访问系统敏感资源。 securetty_types定义 "安全终端"(如 /dev/tty1、/dev/console)对应的 SELinux 类型,限制只有特定类型的终端才能执行敏感操作(如 root 登录)。sepgsql_contexts为 SE-PostgreSQL(PostgreSQL 数据库的 SELinux 增强)定义安全上下文,控制数据库进程对数据文件、端口的访问权限。 snapperd_contexts为 Snapper(Linux 系统快照工具)定义安全上下文,确保快照创建、恢复过程中对文件系统的操作符合 SELinux 策略。 systemd_contexts为 systemd 服务单元定义安全上下文规则,指定不同服务(如 nfs-server.service、httpd.service)启动时的默认进程上下文(如nfsd_t、httpd_t)。userhelper_context为 userhelper工具(辅助普通用户执行特权操作的工具)定义安全上下文,限制userhelper只能执行预设的特权操作,防止权限滥用。users子目录存储不同 SELinux 用户(如 root、staff_u、user_u)的默认上下文配置,每个文件对应一个 SELinux 用户,定义该用户登录后的默认角色(r)、类型(t)等。virtual_domain_context为虚拟化域(如 KVM 虚拟机)定义安全上下文,限制虚拟机进程对宿主机资源的访问,实现虚拟化环境的 SELinux 隔离。 virtual_image_context为虚拟机镜像文件(如 .qcow2文件)定义默认安全上下文,防止镜像文件被未授权进程修改或读取。x_contexts为 X Window 系统(Linux 图形界面)的进程和资源(如窗口、显示设备)定义安全上下文,确保图形界面的访问符合 SELinux 策略。 files 子目录详解(/etc/selinux/targeted/contexts/files/)
该目录是 文件 / 目录安全上下文的核心映射区 ,决定 "特定路径的文件应具备哪种 SELinux 类型"(如
/var/www/html对应httpd_sys_content_t)。
文件名 作用说明 file_contexts默认文件上下文映射文件 ,系统预装的 "路径 - 类型" 映射规则,覆盖绝大多数系统路径(如 /etc对应etc_t、/home对应user_home_dir_t),是文件上下文的 "基础规则库"。file_contexts.binfile_contexts的二进制编译版本 ,由系统自动生成,SELinux 运行时优先加载二进制文件(加载速度更快),文本文件file_contexts是二进制文件的 "源配置"。file_contexts.homedirs为用户家目录(如 /home/user、/root)定义默认上下文映射,细化家目录内不同子路径的类型(如/home/user/Documents对应user_home_t)。file_contexts.homedirs.binfile_contexts.homedirs的二进制编译版本,作用同file_contexts.bin。file_contexts.local用户自定义文件上下文映射文件 ,优先级高于 file_contexts,用户通过semanage fcontext命令添加的自定义规则会写入此文件,用于覆盖默认映射(如自定义/data/nfs对应nfs_t)。file_contexts.subs文件路径 "替换规则" 文件,定义路径的简化别名(如将 /var/run映射为/run),确保 SELinux 能识别不同路径别名对应的上下文,避免因路径别名导致的规则失效。file_contexts.subs_distfile_contexts.subs的 "分发版默认文件",系统预装的基础替换规则,用户自定义替换规则需修改file_contexts.subs(而非此文件)。media子目录为媒体设备(如光盘、DVD)定义默认文件上下文,确保挂载媒体设备后,其内部文件的类型符合 SELinux 策略(如光盘文件对应 iso9660_t)。3. policy 子目录(/etc/selinux/targeted/policy/)
存储 SELinux 核心策略文件,是 SELinux 访问控制规则的 "二进制编译结果"。
文件名 作用说明 policy.33SELinux targeted 策略的核心二进制文件 ,包含所有 SELinux 访问控制规则(如 allow允许规则、type_transition类型转换规则),是 SELinux 运行时加载的 "策略本体"。- 后缀33是策略版本号,随系统更新可能变化(如policy.34);- 无法直接用文本编辑器查看,需通过sedispol工具解析为文本规则。
4. SELinux 的工作模式:三种状态(控制严格程度)
SELinux 有三种工作模式,决定了规则的执行强度,是学员必须掌握的基础:
| 模式 | 含义 | 适用场景 | 切换命令(临时) |
|---|---|---|---|
Enforcing |
强制模式:严格执行 SELinux 策略,违反规则的操作会被拒绝并记录日志 | 生产环境(默认模式,必须启用) | setenforce 1 |
Permissive |
宽容模式:不拒绝违反规则的操作,但会记录日志(用于调试策略) | 新服务部署、排查 SELinux 相关问题时 | setenforce 0 |
Disabled |
禁用模式:完全关闭 SELinux(不加载策略,不记录日志) | 仅临时测试(不推荐生产环境,需重启生效) | 需修改 /etc/selinux/config 并重启 |
- 关键区别 :
Permissive是 "记录不阻止",Disabled是 "不记录不阻止";Disabled需重启才能切换到其他模式,而Enforcing和Permissive可通过setenforce实时切换。
三、SELinux 配置管理:掌握 "基本操作"
这部分是实操基础,学员需掌握 "查看状态、修改模式、管理安全上下文、调整布尔值" 等核心命令,为后续排错铺垫。
1. 查看 SELinux 状态
# 1. 查看整体状态(模式、策略类型等)
sestatus
# 输出示例:
# 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
# Policy deny_unknown status: allowed
# 2. 查看当前工作模式(简洁)
getenforce
# 输出:Enforcing / Permissive / Disabled
2. 修改 SELinux 工作模式
(1)临时修改(立即生效,重启后失效)
setenforce 0 # 切换到 Permissive 模式(宽容)
setenforce 1 # 切换到 Enforcing 模式(强制)
(2)永久修改(需重启生效,修改配置文件)
vim /etc/selinux/config
# 核心配置:
# SELINUX=enforcing # 永久启用强制模式(推荐)
# SELINUX=permissive # 永久启用宽容模式(调试)
# SELINUX=disabled # 永久禁用(不推荐)
# 修改后需重启系统生效
reboot

3. 安全上下文管理(核心操作)
(1)查看安全上下文
# 查看文件/目录的安全上下文
ls -Z /var/www/html
# 输出示例:-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.html
# 查看进程的安全上下文(主体 type)
ps -Z | grep httpd
# 输出示例:system_u:system_r:httpd_t:s0 1234 ? 00:00:00 httpd
(2)修改安全上下文(两种方式)
方式 1:chcon 临时修改(重启或 restorecon 后失效)
# 格式:chcon [选项] 安全上下文 目标文件
# 示例:将 /data/web 的类型改为 httpd_sys_content_t(让 httpd 可访问)
chcon -t httpd_sys_content_t /data/web
方式 2:semanage 永久修改(写入策略,推荐)
chcon 是临时修改,semanage 会将修改保存到 SELinux 策略数据库,重启后不失效:
# 1. 安装 semanage 工具(默认可能未安装)
yum install policycoreutils-python -y
# 或 yum install policycoreutils-python-utils -y(CentOS 8+)
# 2. 永久修改目录的类型(-a 新增,-t 指定类型,-r 递归)
semanage fcontext -a -t httpd_sys_content_t "/data/web(/.*)?"
# 注:"/data/web(/.*)?" 表示匹配 /data/web 及所有子目录文件
# 3. 应用修改(让策略生效)
restorecon -Rv /data/web # -R 递归,-v 显示详细信息
- 关键区别 :
chcon适合临时测试,semanage + restorecon适合永久配置(生产环境必用)。
4. 布尔值(Booleans)管理:快速调整策略开关
SELinux 预定义了大量 "布尔值"(开关),用于快速启用 / 禁用特定规则(无需修改安全上下文),是解决服务访问问题的常用手段。
SELinux 布尔值(Boolean)是 控制 SELinux 策略中 "条件性规则" 的开关变量 ,用于动态调整进程的权限范围。它们相当于 "策略中的配置项",通过开启(on)或关闭(off),可以在不修改核心策略的前提下,灵活允许或禁止特定场景的访问行为(如允许 httpd 访问网络、执行脚本等)。

5. 端口标签管理:允许服务使用非标准端口
SELinux 不仅限制文件访问,还限制进程监听的端口(每个端口有 "端口类型" 标签)。例如,httpd 默认只能监听 http_port_t 类型的端口(如 80、443),若想让 httpd 监听 8080 端口,需将 8080 端口的类型改为 http_port_t。
# 1. 查看当前允许 httpd 监听的端口类型及端口
semanage port -l | grep http_port_t
http_port_t tcp 80, 443, 488, 8008, 8009, 8443
# 2. 永久添加 8080 端口到 http_port_t 类型
semanage port -a -t http_port_t -p tcp 8080
# 移除端口标签 需 root 权限
semanage port -d -t http_port_t -p tcp 8080
# 3. 验证添加结果
semanage port -l | grep http_port_t # 此时会显示 8080
四、SELinux 实践操作:从 "理论" 到 "解决问题"
这是教学重点,通过 "服务访问故障排查" 案例,让学员掌握 "SELinux 导致的问题如何定位和解决",避免遇到问题就禁用 SELinux。
在 SELinux 中,"主体(如进程)的 type 类型" 与 "客体(如文件、端口)的 type 类型" 是否 "匹配",本质是指 SELinux 策略中是否存在允许主体 type 访问客体 type 的规则 (即 allow 规则)。若存在允许规则,则认为 "类型匹配"(主体可合法访问客体);若不存在,则 "不匹配"(访问会被阻止)。
判断步骤:3 步确认类型是否匹配
步骤 1:获取主体(进程)的 type 类型
主体通常是进程,通过 ps -eZ 命令查看进程的 SELinux 上下文,其中 第三个字段即为主体的 type。
示例:查看 httpd 进程的 type
ps -eZ | grep httpd
输出类似:
system_u:system_r:httpd_t:s0 1234 ? 00:00:00 httpd
→ 主体(httpd 进程)的 type 是 httpd_t。
步骤 2:获取客体(资源)的 type 类型
客体可以是文件、目录、端口等,根据资源类型使用不同命令查看,第三个字段即为客体的 type。
| 客体类型 | 查看命令示例(获取 type) | 说明 | |
|---|---|---|---|
| 文件 / 目录 | ls -Z /var/www/html |
查看 /var/www/html 的 type |
|
| 端口 | `semanage port -l | grep http` | 查看 http 相关端口的 type |
示例:查看 /var/www/html 文件的 type
ls -Z /var/www/html
输出类似:
unconfined_u:object_r:httpd_sys_content_t:s0 index.html
→ 客体(文件)的 type 是 httpd_sys_content_t。
步骤 3:检查策略中是否存在允许访问的规则
通过 sesearch 工具(需安装 setools-console 包)查询 SELinux 策略中是否有允许 "主体 type 访问客体 type" 的规则。
核心语法:
sesearch -A -s 主体type -t 客体type -c 资源类别
-
-A:仅显示allow规则(允许访问的规则); -
-s:指定主体 type(如httpd_t); -
-t:指定客体 type(如httpd_sys_content_t); -
-c:指定资源类别(如file表示文件,port表示端口,process表示进程等)。
实验1:SELinux端口限制实践
步骤1:确保nginx服务正在运行
[root@rhce ~]# systemctl is-active nginx.service
active
步骤2:查看nginx进程的上下文
[root@rhce ~]# ps -axZ | grep nginx
system_u:system_r:httpd_t:s0 12495 ? Ss 0:00 nginx: master process /usr/sbin/nginx
system_u:system_r:httpd_t:s0 12496 ? S 0:00 nginx: worker process
system_u:system_r:httpd_t:s0 12497 ? S 0:00 nginx: worker process
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 12516 pts/0 S+ 0:00 grep --color=auto nginx
步骤3:停止nginx服务并查看状态
[root@rhce ~]# systemctl stop nginx.service
[root@rhce ~]# systemctl is-active nginx.service
inactive
步骤4:查看SELinux允许nginx侦听端口
[root@rhce ~]# semanage port -l | grep http
http_cache_port_t tcp 8080, 8118, 8123, 10001-10010
http_cache_port_t udp 3130
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
pegasus_http_port_t tcp 5988
pegasus_https_port_t tcp 5989
步骤5:修改nginx服务的监听端口为82
[root@rhce ~]# vim /etc/nginx/nginx.conf
listen 82;
步骤6:再次启动httpd服务
[root@rhce ~]# systemctl restart nginx.service
Job for nginx.service failed because the control process exited with error code.
See "systemctl status nginx.service" and "journalctl -xeu nginx.service" for details.
步骤7:查看SELinux日志
[root@rhce ~]# grep "nginx" /var/log/audit/audit.log | grep "denied"
type=AVC msg=audit(1762831604.791:139): avc: denied { name_bind } for pid=12769 comm="nginx" src=82 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:reserved_port_t:s0 tclass=tcp_socket permissive=0
SELinux 阻止 Nginx 进程的原因是:Nginx 进程(类型
httpd_t)尝试绑定 82 端口(类型reserved_port_t),但 SELinux 策略中没有 "允许httpd_t对reserved_port_t类型的tcp_socket执行name_bind权限" 的规则。具体来说:
82 端口属于 1-1024 特权端口,SELinux 默认将其标记为
reserved_port_t类型;Nginx 进程的类型被错误标记为
httpd_t(正常应为nginx_t),而httpd_t类型的进程默认没有绑定reserved_port_t端口的权限(name_bind);因此 SELinux 在强制模式下直接拒绝了绑定操作,导致 Nginx 无法启动或监听 82 端口。
步骤8:配置SELinux允许nginx侦听端口82
[root@rhce ~]# semanage port -a -t http_port_t -p tcp 82
# 添加 82 到 http_port_t
[root@rhce ~]# semanage port -l | grep http
http_cache_port_t tcp 8080, 8118, 8123, 10001-10010
http_cache_port_t udp 3130
http_port_t tcp 82, 80, 81, 443, 488, 8008, 8009, 8443, 9000
pegasus_http_port_t tcp 5988
pegasus_https_port_t tcp 5989
步骤9:重启nginx
[root@rhce ~]# systemctl restart nginx.service
实验2:SELinux类型限制实践-管理安全上下文
步骤1:临时修改SELinux模式为Permissive
[root@rhce ~]# setenforce 0
[root@rhce ~]# getenforce
Permissive
[root@rhce ~]#
步骤2:创建nginx主页面
[root@rhce ~]# mkdir /web
[root@rhce ~]# echo 123 > /web/index.html
步骤3:修改nginx配置
[root@rhce ~]# vim /etc/nginx/nginx.conf
root /web;
步骤4:重新加载配置并验证
[root@rhce ~]# systemctl restart nginx.service
步骤5:修改SELinux模式为Enforcing
[root@rhce ~]# setenforce 1
[root@rhce ~]# getenforce
Enforcing
步骤6:查看SELinux日志
[root@rhce ~]# systemctl restart nginx.service
[root@rhce ~]# curl 192.168.223.5:82
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.20.1</center>
</body>
</html>
[root@rhce ~]# grep "nginx" /var/log/audit/audit.log | grep "denied"
type=AVC msg=audit(1762833229.314:150): avc: denied { getattr } for pid=12909 comm="nginx" path="/web/index.html" dev="dm-0" ino=237647 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0
这条日志的关键是 "类型不匹配":
进程类型(
httpd_t)和文件类型(default_t)都不符合 Web 服务的 SELinux 配置规范;解决的核心思路是 "让文件类型适配进程类型"(或修正进程类型),让 SELinux 策略中的允许规则生效。
日常排查时,只要看到
avc: denied { getattr }+ 文件路径 + 类型为default_t,优先修正文件的 SELinux 类型即可快速解决。
步骤7:修改index.html类型
[root@rhce ~]# semanage fcontext -a -t httpd_sys_content_t /web/index.html
[root@rhce ~]# ll -Z /web/index.html
-rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 4 Nov 11 11:49 /web/index.html
[root@rhce ~]# restorecon -R -v /web/index.html
Relabeled /web/index.html from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
步骤8:再次验证实验结果
[root@rhce ~]# curl 192.168.223.5:82
123
实验3:SELinux类型限制实践-布尔值修改
步骤1:安装、配置nginx的资源目录是/home/redhat
[root@rhce ~]# yum install nginx -y
[root@rhce ~]# systemctl restart nginx
[root@rhce ~]# vim /etc/nginx/conf.d/test.conf
server {
listen 84;
root /home/redhat;
}
[root@rhce ~]# echo "home redhat" > /home/redhat/index.html
*[root@rhce ~]# chmod 755 /home/redhat
*[root@rhce ~]# chmod 644 /home/redhat/index.html
步骤2:重启Nginx,发现失败
[root@rhce ~]# systemctl restart nginx.service
Job for nginx.service failed because the control process exited with error code.
See "systemctl status nginx.service" and "journalctl -xeu nginx.service" for details.
[root@rhce ~]# grep "nginx" /var/log/audit/audit.log | grep "denied"
type=AVC msg=audit(1762837067.091:122): avc: denied { name_bind } for pid=2055 comm="nginx" src=84 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:reserved_port_t:s0 tclass=tcp_socket permissive=0
步骤3:配置SELinux允许nginx侦听端口84、修改目标资源类型
[root@rhce ~]# semanage port -a -t http_port_t -p tcp 84
[root@rhce ~]# semanage fcontext -a -t httpd_sys_content_t "/home/redhat(/.*)?"
[root@rhce ~]# restorecon -R -v /home/redhat/
Relabeled /home/redhat from unconfined_u:object_r:user_home_dir_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
Relabeled /home/redhat/.bash_logout from unconfined_u:object_r:user_home_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
Relabeled /home/redhat/.bash_profile from unconfined_u:object_r:user_home_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
Relabeled /home/redhat/.bashrc from unconfined_u:object_r:user_home_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
Relabeled /home/redhat/index.html from unconfined_u:object_r:user_home_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
root@rhce ~]# systemctl start nginx
[root@rhce ~]# curl 192.168.223.5:84
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.20.1</center>
</body>
</html>
[root@rhce ~]# yum install setroubleshoot -y
实验成功即显示结果:
步骤4:
[root@rhce ~]# ausearch -m AVC -c nginx --raw | audit2allow -M nginx_access_home
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i nginx_access_home.pp
[root@rhce ~]# semodule -i nginx_access_home.pp
ausearch -m AVC -c nginx --raw从 SELinux 审计日志(/var/log/audit/audit.log)中,筛选出与 Nginx 相关的 "访问拒绝事件(AVC)",并以原始格式输出。 核心是 "抓出 Nginx 被 SELinux 拦下来的操作"(比如 "想读文件被拒""想进目录被拒")。
audit2allow -M nginx_access_home接收前一段的拒绝日志,自动分析 "谁(Nginx 进程)需要什么权限",生成两个文件:
nginx_access_home.te:策略源码文件(人类可读,记录具体允许规则);
nginx_access_home.pp:编译后的二进制策略包(可直接加载到 SELinux)。→ 核心是 "把'被拒绝的操作'变成'允许的规则'"。
步骤5:
[root@rhce ~]# curl http://192.168.223.5:84
home redhat
linux:
windows:

