
我们经常使用 CentOS 7.9 来搭建 Web 服务、数据库、缓存等业务系统。随着安全要求的提高,SELinux(Security‑Enhanced Linux)作为内核级 Mandatory Access Control(强制访问控制)机制,成为默认安全策略框架。但初次启用 SELinux 时,经常会遇到某些业务目录无法访问的问题 ------ 即便权限、所属用户/组设置正确,服务仍因 SELinux 拒绝访问而报错。
A5数据将深度讲解如何定位 SELinux 拒绝访问日志、分析原因、设置正确的策略,并提供完整的实现步骤、命令示例、策略模块制作和常见误区总结。
一、场景背景(真实机房故障复现)
我们一台部署于香港数据中心(机架香港服务器www.a5idc.com,双路 Intel Xeon、SSD、RAID10)的 CentOS 7.9 业务服务器:
| 参数项 | 详细说明 |
|---|---|
| 主机名 | web‑app‑01.dc01.example.com |
| 处理器 | 2× Intel® Xeon® Silver 4210 @ 2.20GHz |
| 内存 | 128 GB DDR4 RDIMM |
| 存储 | 2× 1 TB NVMe SSD(RAID1) |
| 操作系统 | CentOS Linux 7.9.2009 x86_64 |
| SELinux 状态 | enforcing |
| 业务服务 | Apache httpd 2.4.6、PHP7.4 |
| 访问目录 | /var/www/custom_site |
业务需求是在 /var/www/custom_site 目录下部署自定义站点。但访问该站点时发现:
- Apache 报 403 Forbidden
- 查看日志未发现典型权限错误
- 将 SELinux 临时设为 permissive 后,访问恢复
因此确定是 SELinux 拒绝访问导致须配置策略允许访问。
二、SELinux 基础回顾
SELinux 是 Linux 内核中的强制访问控制(MAC)系统,由 NSA 和社区合作开发。其核心概念包括:
- Type Enforcement(类型强制):最常用的策略形式,通过 subject(进程 type)与 object(文件 type)间的允许规则来控制访问。
- Booleans :开关形式的策略标记,如
httpd_enable_homedirs。 - File Context(文件上下文) :文件的安全类型标签,例如
httpd_sys_content_t允许 HTTPD 访问。
可以通过以下命令查看当前状态:
bash
# 查看 SELinux 当前模式
sestatus
如输出:
SELinux status: enabled
SELinuxfs mount: /selinux
Current mode: enforcing
Mode from config file: enforcing
Policy version: 31
Policy from config file: targeted
三、定位 SELinux 拒绝访问日志
当 SELinux 拒绝访问时,会记录 AVC(Access Vector Cache)拒绝日志,我们可通过以下方式定位:
bash
# 实时查看最新的 SELinux AVC 拒绝
ausearch -m AVC,USER_AVC -ts recent
或者过滤 httpd 相关拒绝:
bash
grep httpd /var/log/audit/audit.log | grep denied
典型拒绝日志片段如下:
type=AVC msg=audit(1610000000.123:456): avc: denied { read open } for pid=1234
comm="httpd" name="custom_site" dev="dm‑0" ino=1234567
scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0
tclass=dir permissive=0
分析上述日志:
scontext=httpd_t→ 表示是由 Apache 访问tcontext=user_home_t→ 目标目录当前被标记为用户家目录类型- 拒绝的动作是
read open→ 读取打开操作
可以初步判断是当前文件上下文类型不对。
四、核心问题分析
CentOS 默认 httpd 只允许访问以下类型的目录:
| 路径 | 默认 SELinux 类型 | 允许 httpd 访问 |
|---|---|---|
/var/www/html |
httpd_sys_content_t |
是 |
/srv/www |
httpd_sys_content_t |
是 |
用户自定义目录 /var/www/custom* |
可能被标记成 default_t 或 user_home_t |
否 |
因此需要将该目录上下文更改为 httpd_sys_content_t,并在需要的情况下启用相关 boolean。
五、解决思路与方法
方法 1:设置目录 SELinux 文件上下文
bash
# 安装 semanage(若未安装)
yum install -y policycoreutils-python
# 查看当前 context
ls -ldZ /var/www/custom_site
若显示:
drwxr-xr-x. root root unconfined_u:object_r:user_home_t:s0 custom_site/
则需修改为 HTTPD 可访问的类型:
bash
# 递归设置类型
semanage fcontext -a -t httpd_sys_content_t "/var/www/custom_site(/.*)?"
# 应用更改
restorecon -Rv /var/www/custom_site
上述命令解释:
semanage fcontext -a→ 添加策略-t httpd_sys_content_t→ 目标类型是 HTTPD 系统内容- 正则
/var/www/custom_site(/.*)?→ 匹配目录及其下所有内容 restorecon→ 真正将上下文写入 inode
验证:
bash
ls -lZ /var/www/custom_site
输出示例:
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 custom_site/
方法 2:针对写权限等 boolean 设置
若业务是动态脚本写入目录(如上传),则需要额外调整:
| Boolean 名称 | 作用 |
|---|---|
httpd_enable_homedirs |
允许访问用户 home 目录 |
httpd_unified |
将 httpd 脚本写入内容的策略放宽 |
httpd_sys_script_rw_t |
允许脚本读写文件 |
启用示例:
bash
setsebool -P httpd_unified 1
注意:开启写权限前需确认目录 context 已设置为
httpd_sys_rw_content_t(如上传目录)。
六、制定自定义策略模块
在少数场景下,业务访问仍被拒绝,这时可以生成定制策略:
bash
# 实际触发拒绝后,生成本地模块
grep httpd /var/log/audit/audit.log | audit2allow -M local_httpd
# 查看模块文件
ls local_httpd.pp local_httpd.te
# 安装策略模块
semodule -i local_httpd.pp
文件示例 local_httpd.te:
te
module local_httpd 1.0;
require {
type httpd_t;
type user_home_t;
class dir { read open };
}
#============= httpd_t ==============
allow httpd_t user_home_t:dir { read open };
该策略明确允许 httpd 访问
user_home_t类型的目录。该方法应作为最后手段,优先使用正确上下文替换。
七、完整落地脚本示例(细粒度)
bash
#!/bin/bash
TARGET_DIR="/var/www/custom_site"
# 1. 安装所需工具
yum install -y policycoreutils-python
# 2. 检查并备份 context
echo "原 context:"
ls -lZ "$TARGET_DIR"
# 3. 设置 HTTPD 可访问类型
semanage fcontext -a -t httpd_sys_content_t "${TARGET_DIR}(/.*)?"
restorecon -Rv "$TARGET_DIR"
# 4. 必要写权限目录设置
UPLOAD_DIR="${TARGET_DIR}/uploads"
mkdir -p "$UPLOAD_DIR"
semanage fcontext -a -t httpd_sys_rw_content_t "${UPLOAD_DIR}(/.*)?"
restorecon -Rv "$UPLOAD_DIR"
# 5. 启用 write 相关 boolean
setsebool -P httpd_unified 1
echo "更新后 context:"
ls -lZ "$TARGET_DIR"
ls -lZ "$UPLOAD_DIR"
八、验证访问与常见误区排查
访问验证
-
访问站点是否仍然 403:
- 若访问成功,则策略有效
- 若仍然拒绝,检查 audit 日志是否还有新的 AVC 拒绝
-
动态内容(上传)测试:
- 上传文件后能否写入并被读取
九、总结与最佳实践
| 典型问题 | 原因 | 解决方式 |
|---|---|---|
| 403 Forbidden | SELinux 拒绝访问 | 修改目录 SELinux 类型 |
| 写权限被拒绝 | 未启用对应 boolean | setsebool httpd_unified 1 |
| 自定义规则不足 | 缺失策略 | 生成 local 模块 |
要点回顾:
- 优先使用正确上下文替换,避免滥用放宽策略。
- 慎用 Boolean 开关,理解其作用与范围。
- 日志是关键:通过 audit 日志定位 AV 执行链。
- 生产服务器变更需复现验证,建议在测试机先行验证策略。
十、附录
常用 SELinux 命令
| 命令 | 作用 |
|---|---|
sestatus |
查看状态 |
getsebool -a |
列出所有 boolean |
semanage fcontext -l |
列出所有文件 context |
restorecon -Rv /path |
恢复文件 context |
audit2allow -M mod |
生成策略模块 |
semodule -l |
列出已载入模块 |