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:

相关推荐
cccccc语言我来了2 小时前
深入理解 Linux(7) 命令与动态库:从文件操作到程序链接的实践指南
android·linux·运维
Lynnxiaowen2 小时前
今天我们开始学习Linux自动化运维Ansible基础
linux·运维·学习·自动化·云计算·ansible
NiKo_W2 小时前
Linux 传输层协议
linux·运维·网络·tcp协议·传输层·udp协议
夜月yeyue2 小时前
Linux 中断处理机制详解:上下半部、内核线程与中断线程化
linux·运维·单片机·嵌入式硬件·uboot·bootloard
浪漫血液&2 小时前
Linux基础指令(简易版)
linux·服务器
云计算老刘3 小时前
1. Cockpit 管理服务器;2. Linux 软件包管理
linux·运维·服务器·云原生·云计算
小苏兮3 小时前
【把Linux“聊”明白】进程的概念与状态
linux·运维·服务器·学习
wsad05324 小时前
Ubuntu 24.04 更换国内软件源(以阿里云为例)
linux·ubuntu·阿里云
楼田莉子4 小时前
C++/Linux小项目:自主shell命令解释器
linux·服务器·开发语言·c++·后端·学习