SELinux是什么? @

SELinux可以想象是Linux系统的“超级保安”,核心是给文件、进程、端口等所有资源“贴标签”,再通过严格的访问规则,限制资源间的交互。哪怕你有系统最高权限(root),不符合规则也无法操作不属于自己的资源。

或许有人疑惑:Linux不是已有rwx文件权限和用户权限了吗?两者的区别可以用一个比喻理解:

  • 传统权限:像小区门禁卡,有卡就能进小区,但进了之后可随意触碰公共设施、尝试开他人家门,权限边界模糊。
  • SELinux:给小区每一户、每样物品都贴了专属标识,还明确规定“只有3栋201的住户,能开自己家的门、用自己家的家电”,哪怕你有门禁卡(root),也不能越界,安全性直接拉满。

SELinux核心逻辑 @

SELinux的工作原理并不复杂,核心就两件事:给资源贴标签,按预设规则判断是否允许访问。它与传统权限并行工作,且优先级更高,只要SELinux阻断访问,哪怕传统权限全开也无济于事。

SELinux给系统中所有对象(文件、进程、端口等)都贴了一个安全上下文标签,访问时先核对标签,再校验传统权限。标签格式为 用户:角色:类型:级别,日常场景中前三者最常用,级别仅用于特殊强制访问模式(MLS/MCS)。

标签各部分含义拆解:

  • 用户(User) :SELinux专属用户,非系统普通用户(如root)。比如系统root用户对应SELinux用户sysadm_u,普通用户对应user_u,用于区分安全主体身份。
  • 角色(Role) :类似“权限分组”,控制主体能切换的类型范围。比如sysadm_r(管理员角色)、user_r(普通用户角色),避免主体越权切换到高权限类型。
  • 类型(Type) :最核心部分,进程的类型称为“域”,文件的类型直接叫“类型”,访问规则全围绕类型制定。例如httpd进程的域是httpd_t,网站文件的类型是httpd_sys_content_t,规则明确“httpd_t域的进程,仅能访问httpd_sys_content_t类型的文件”。

示例命令如下,需要注意如果系统关闭了SELinux,则其标签会显示为? 有些系统默认没有安装SElinux而是使用AppArmor,比如我的manjaro

# 查看文件/目录标签
ls -Z {path}
# 输出可能为 unconfined_u:object_r:httpd_sys_content_t:s0 index.html,符合<用户:角色:类型:级别>的格式
# 如果输出为?则说明该文件不存在SELinux标签

# 查看进程标签
ps -Z {name}
# 输出可能为 system_u:system_r:httpd_t:s0  1234 ?  00:00:01 httpd
# httpd_t即为进程域标签,需与文件标签对应才能正常访问

# 查看端口标签
semanage port -l | grep {port}
# 输出可能为 http_port_t  tcp 80, 443, 488, 8008, 8009, 8443
# 说明80端口属于http_port_t类型,允许httpd进程使用

类型强制(TE)策略 @

SELinux的核心规则是“类型强制”,简单说就是:只有进程的域(类型)和文件的类型匹配预设规则,访问才被允许。系统默认自带了httpd、mysql、ssh等常见服务的规则,无需手动编写。

举个例子:httpd进程(域httpd_t)访问/var/www/html下的文件,需满足两个条件:

  1. 传统权限中httpd用户有读权限(如 chmod 644 index.html
  2. 文件类型为httpd_sys_content_t

若将网站文件复制到/home目录(默认类型user_home_t),执行cp index.html /home/ 后,用 ls -Z /home/index.html 会看到标签为 unconfined_u:object_r:user_home_t:s0 index.html,哪怕给文件开全权限(chmod 777 /home/index.html),SELinux也会阻断访问,浏览器报403错误,核心原因就是httpd_t域与user_home_t类型无允许规则。

SELinux的三种工作模式 @

SELinux不止“开启/关闭”两种状态,还有宽容模式,三种模式可灵活切换,适配不同场景需求。

  1. 强制模式(Enforcing) :核心工作模式,严格执行所有规则,不匹配则阻断访问并记录日志(日志路径:/var/log/audit/audit.log),生产环境建议长期开启。
  2. 宽容模式(Permissive) :不强制执行规则,允许越权操作但记录日志,适合调试场景。比如服务访问异常时,切换到此模式可快速判断是否为SELinux阻断。
  3. 关闭模式(Disabled) :完全关闭SELinux,不贴标签、不执行规则,安全性大幅下降。仅当老旧软件完全不兼容SELinux时才考虑关闭(极不推荐)。

查看与切换模式 @

  • 查看当前模式:getenforce,输出为Enforcing、Permissive或Disabled
  • 临时切换(重启失效):setenforce 0(切宽容模式)、setenforce 1(切强制模式)
  • 永久切换(重启生效):编辑配置文件/etc/selinux/config,修改 SELINUX= 后的内容(Enforcing/Permissive/Disabled),保存后重启系统

SELinux常用操作 @

日常使用中,最常见的问题是SELinux阻断服务访问。

查看SELinux阻断日志 @

服务异常时,优先查看审计日志,确认是否为SELinux阻断:

基础命令:grep "AVC" /var/log/audit/audit.log(AVC是SELinux访问控制日志标识)。

示例日志:type=AVC msg=audit(1690000000.123:456): avc: denied { read } for pid=1234 comm="httpd" name="index.html" dev="sda1" ino=789 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file

日志解读:comm=“httpd"表示是httpd进程,scontext(进程标签)为httpd_t,tcontext(文件标签)为user_home_t,明确是域与类型不匹配导致阻断。

ausearch工具介绍 @

ausearch主要用于快速定位审计日志中的关键事件,尤其适合排查SELinux阻断(AVC事件)、用户操作、文件变更等场景,常见用法如下:

  • 查看最近的SELinux阻断日志ausearch -m AVC -ts recent 参数说明:-m AVC 表示仅过滤SELinux访问控制(AVC)事件,-ts recent 表示筛选最近发生的事件,避免遍历整个日志文件,快速定位阻断原因
  • 结合audit2why分析阻断原因ausearch -m AVC -ts recent | audit2why 将ausearch过滤后的阻断日志,通过管道传给audit2why工具,可自动解析日志并给出解决方案(如“需将文件类型改为httpd_sys_content_t”),无需手动解读复杂日志字段
  • 按关键词筛选日志ausearch -k user-modify -i 参数说明:-k 后跟自定义关键词(如审计规则中设置的key_name),-i 表示将日志中的编码字段转为易读格式,适合排查特定操作的审计记录(如用户创建、文件修改)

更多用法可以参考 从coredump到auditd审计的完整指南 文章的内容

调整文件/目录类型标签 @

若因文件类型错误导致阻断,可手动修改标签,分临时和永久两种场景。

临时修改:命令 chcon -t 目标类型 路径

# 例如httpd访问/home/index.html被拒问题,可使用如下命令
chcon -t httpd_sys_content_t /home/index.html`
# 验证标签已改为httpd\_sys\_content\_t,此时httpd可正常访问,但重启后标签会恢复默认。
ls -Z /home/index.html

永久修改

  • semanage fcontext -a -t 目标类型 路径(添加标签规则,路径后加(/.*)?表示包含子文件/目录)
  • restorecon -Rv 路径(刷新标签,-R递归处理,-v显示详细过程)
# 永久修改/home/www目录标签
semanage fcontext -a -t httpd_sys_content_t /home/www(/.*)?
restorecon -Rv /home/www

如果semanage工具默认未安装,CentOS/RHEL执行 yum install policycoreutils-python-utils,Ubuntu执行 apt install policycoreutils 安装

调整端口类型标签 @

SELinux对端口有类型限制,如httpd默认仅能使用http_port_t类型的端口(80、443等),若改用其他端口需手动配置。

  • 永久添加端口类型:semanage port -a -t 目标类型 -p 协议 端口号
# 让httpd使用8080端口
semanage port -a -t http_port_t -p tcp 8080
# 验证8080已加入列表
semanage port -l | grep http_port_t
  • 删除端口类型:semanage port -d -t 目标类型 -p 协议 端口号,适合不再使用该端口的场景。

操作SELinux布尔值 @

布尔值是SELinux的“规则开关”,可快速调整访问规则,无需修改标签,适合灵活适配场景。

  • 查看所有布尔值:getsebool -a,输出格式如httpd_enable_homedirs --> off(表示禁止httpd访问用户家目录)。
  • 过滤指定服务布尔值:getsebool -a | grep 服务名,如 getsebool -a | grep httpd
  • 临时开启布尔值:setsebool 布尔值 on(重启失效),如允许httpd访问家目录,执行 setsebool httpd_enable_homedirs on
  • 永久开启布尔值:setsebool -P 布尔值 on(-P参数表示永久生效)

经验总结 @

  • 线上环境不要轻易关闭SELinux:遇到阻断问题就关闭SELinux是高危操作,容易触发安全风险。
  • 临时标签易失效chcon修改的标签在重启或执行 restorecon 后会恢复默认。
  • 新挂载目录需同步标签:挂载新硬盘/目录后,默认标签可能为default_t(服务无法访问),需执行 restorecon -Rv 挂载点 刷新标签。
  • 系统差异需注意:CentOS/RHEL默认开启SELinux,Manjaro默认不安装SELinux,改用AppArmor。

SELinux和AppArmor都是Linux强制访问控制工具,但设计思路不同,适配场景有差异