SELinux

一、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 访问控制的两步判定流程,核心内容翻译与提炼如下:

  1. 第一步:Linux 原生 DAC 检查 "SELinux 并非替代 Linux 传统的自主访问控制(DAC),而是在其基础上增加强制访问控制(MAC)。当一个进程(主体)尝试访问一个文件或资源(客体)时,内核会首先执行 DAC 检查 ------ 即校验文件的所有者、组、其他用户的 rwx 权限(如 chmod 配置的权限)。若 DAC 检查失败(例如,普通用户尝试修改 root 所有的只读文件),内核会直接返回 EACCES(权限拒绝)错误,且不会触发后续的 SELinux MAC 检查。"

  2. 第二步: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(多级安全)策略,标识资源的 "敏感程度"(如 s0s1: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_urootstaff_u等文件,对应的是SELinux 用户(SELinux User) ------ 这是 SELinux 安全模型中用于身份标识的抽象概念,与 Linux 系统用户(如 /etc/passwd 中的用户)并非直接对应,而是通过映射关系关联(如 Linux 的 root 用户默认映射到 SELinux 的 root 用户)

查映射:用 semanage login -l 看 Linux 用户对应哪个 SELINUX 用户;

角色(system_runconfined_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 用户 对应文件 典型用途 权限等级
root root 对应 Linux 系统的 root 管理员,是 SELinux 中权限最高的用户,可切换到几乎所有角色(如 sysadm_runconfined_r),用于系统核心管理操作。 最高(可执行敏感操作,如修改系统配置、管理服务)
unconfined_u unconfined_u 对应 Linux 中 "无限制用户"(如普通用户但需较高权限),默认关联 unconfined_r(无限制角色),权限接近 root 但受部分限制,适合信任的普通用户。 高(允许大部分操作,无需严格遵循 SELinux 类型限制)
sysadm_u sysadm_u 系统管理员专用 SELinux 用户,关联 sysadm_r(系统管理员角色),权限聚焦于系统管理(如启停服务、管理用户),但比 root 更受限(避免无差别高权限)。 中高(仅允许系统管理相关操作)
staff_u staff_u 对应 "Staff 角色用户"(如中级运维人员),关联 staff_r 角色,权限介于管理员和普通用户之间,可执行部分管理操作(如 su 提权)但受严格限制。 中等(有限的管理权限,核心操作需授权)
user_u user_u 普通受限用户,关联 user_r 角色,权限仅限于个人操作(如访问家目录、使用普通应用),无法执行系统管理操作,适合一般用户。 低(仅允许个人级操作)
guest_u guest_u 临时访客用户,权限极低,仅允许最基础的操作(如浏览网页、读取公共文件),无法修改系统或个人配置,适合临时登录场景。 极低(严格限制,防止任何敏感操作)
xguest_u xguest_u 图形界面下的访客用户,专为图形登录设计,权限与 guest_u 类似,但额外限制图形界面相关操作(如禁止修改桌面配置),适合公共电脑的临时使用。 极低(图形场景的访客权限)

二、SELinux 用户与角色(Role)的区别

SELinux 中,"用户" 和 "角色" 是两个不同层级的安全概念,核心区别体现在 "范围" 和 "关联关系" 上:

维度 SELinux 用户(User) SELinux 角色(Role)
定义 抽象的身份标识,代表 "谁在操作"(如 rootuser_u)。 操作权限的 "角色定位",代表 "扮演什么角色"(如 sysadm_ruser_r)。
核心作用 限制 "允许使用的角色范围"(一个用户可关联多个角色,但不能超出其允许的范围)。 限制 "允许访问的类型(Type)范围"(一个角色关联多个类型,类型决定实际访问权限)。
层级关系 上层概念,是角色的 "容器":用户 → 允许的角色 → 允许的类型。 中层概念,连接用户和类型:角色是用户与类型之间的桥梁。
举例 staff_u(SELinux 用户)允许使用 staff_ruser_r 等角色,但不能使用 sysadm_r(除非授权)。 staff_r(角色)允许访问 staff_tuser_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-minimumselinux-policy-mls

/etc/selinux/ 目录的核心逻辑是 "分层存储、按需加载":

  1. 顶层文件(configsemanage.conf)控制全局模式;

  2. targeted 目录按 "策略开关 - 上下文映射 - 核心策略" 拆分配置,其中 contexts/files 是文件权限的关键,policy/policy.33 是访问规则的本体;

  3. 二进制文件(如 .binpolicy.33)用于 SELinux 高效加载,文本文件(如 file_contextsfile_contexts.local)用于用户配置修改。

日常运维中,修改最多的是 config(启用 / 禁用 SELinux)、file_contexts.local(自定义文件上下文),以及通过 semanage 命令间接修改 loginsseusers 等映射文件。

复制代码
[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 的整体运行模式和管理规则。

文件名 作用说明
config SELinux 主配置文件,控制 SELinux 的启用状态策略类型 ,关键配置项包括:- SELINUX:取值 enforcing(强制模式)、permissive(宽容模式)、disabled(禁用);- SELINUXTYPE:取值 targeted(默认,仅对关键服务生效)、mls(多级安全模式,更严格)。
semanage.conf semanage 命令(SELinux 策略管理工具)的配置文件,定义 semanage 的默认行为,如:- 策略模块的存储路径;- 是否启用审计日志;- 默认的策略类型(与 configSELINUXTYPE 对应)。

二、targeted 子目录(/etc/selinux/targeted/)

targeted 是 RHEL 9 默认的 SELinux 策略类型(对应 configSELINUXTYPE=targeted),该目录存储 targeted 策略的所有具体配置和数据,是 SELinux 策略的核心存储区。

1. 策略开关与映射文件(targeted 目录下直接文件)
文件名 作用说明
booleans.subs_dist SELinux 布尔值(开关)的 "分发版默认映射" 文件,定义系统预装布尔值的默认名称和关联规则,用户一般无需修改(自定义布尔值需通过 semanage boolean 命令)。
logins SELinux 用户与 Linux 系统登录账号的映射配置文件,记录 "哪个 Linux 账号对应哪个 SELinux 用户"(如 root 对应 root SELinux 用户,普通用户默认对应 unconfined_u)。
setrans.conf SELinux 翻译服务(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)允许用户通过 chconsemanage 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.servicehttpd.service)启动时的默认进程上下文(如 nfsd_thttpd_t)。
userhelper_context userhelper 工具(辅助普通用户执行特权操作的工具)定义安全上下文,限制 userhelper 只能执行预设的特权操作,防止权限滥用。
users 子目录 存储不同 SELinux 用户(如 rootstaff_uuser_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.bin file_contexts二进制编译版本 ,由系统自动生成,SELinux 运行时优先加载二进制文件(加载速度更快),文本文件 file_contexts 是二进制文件的 "源配置"。
file_contexts.homedirs 为用户家目录(如 /home/user/root)定义默认上下文映射,细化家目录内不同子路径的类型(如 /home/user/Documents 对应 user_home_t)。
file_contexts.homedirs.bin file_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_dist file_contexts.subs 的 "分发版默认文件",系统预装的基础替换规则,用户自定义替换规则需修改 file_contexts.subs(而非此文件)。
media 子目录 为媒体设备(如光盘、DVD)定义默认文件上下文,确保挂载媒体设备后,其内部文件的类型符合 SELinux 策略(如光盘文件对应 iso9660_t)。
3. policy 子目录(/etc/selinux/targeted/policy/)

存储 SELinux 核心策略文件,是 SELinux 访问控制规则的 "二进制编译结果"。

文件名 作用说明
policy.33 SELinux 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 需重启才能切换到其他模式,而 EnforcingPermissive 可通过 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_treserved_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 进程)需要什么权限",生成两个文件:

  1. nginx_access_home.te:策略源码文件(人类可读,记录具体允许规则);

  2. nginx_access_home.pp:编译后的二进制策略包(可直接加载到 SELinux)。

→ 核心是 "把'被拒绝的操作'变成'允许的规则'"。

步骤5:

复制代码
[root@rhce ~]# curl http://192.168.223.5:84
home redhat
linux:
​

windows:

相关推荐
jimy13 小时前
安卓里运行Linux
linux·运维·服务器
爱凤的小光4 小时前
Linux清理磁盘技巧---个人笔记
linux·运维
耗同学一米八5 小时前
2026年河北省职业院校技能大赛中职组“网络建设与运维”赛项答案解析 1.系统安装
linux·服务器·centos
知星小度S6 小时前
系统核心解析:深入文件系统底层机制——Ext系列探秘:从磁盘结构到挂载链接的全链路解析
linux
2401_890443026 小时前
Linux 基础IO
linux·c语言
智慧地球(AI·Earth)7 小时前
在Linux上使用Claude Code 并使用本地VS Code SSH远程访问的完整指南
linux·ssh·ai编程
老王熬夜敲代码8 小时前
解决IP不够用的问题
linux·网络·笔记
zly35008 小时前
linux查看正在运行的nginx的当前工作目录(webroot)
linux·运维·nginx
QT 小鲜肉8 小时前
【Linux命令大全】001.文件管理之file命令(实操篇)
linux·运维·前端·网络·chrome·笔记
问道飞鱼9 小时前
【Linux知识】Linux 虚拟机磁盘扩缩容操作指南(按文件系统分类)
linux·运维·服务器·磁盘扩缩容