# SELinux 配置

URL: https://caijiao.org/rockylinux/selinux-config
Source: docs/rockylinux/selinux-config.md
Description: 详细介绍 Rocky Linux 中 SELinux（安全增强型 Linux）的工作原理、配置方法和常见问题排查

SELinux（Security-Enhanced Linux，安全增强型 Linux）是一个由美国国家安全局（NSA）开发的强制访问控制（MAC）安全机制，它为 Linux 内核提供了额外的安全层。本教程将详细介绍 SELinux 的工作原理、配置方法以及常见问题的排查。

## SELinux 概述

SELinux 是一种基于域-类型模型（domain-type model）的强制访问控制系统。与传统的 Linux 自主访问控制（DAC）不同，SELinux 不仅基于用户和组权限，还基于标签（labels）来控制进程对文件、端口和其他系统资源的访问。

### SELinux 的主要特点

1. **强制访问控制（MAC）**：超越传统的用户-组-其他权限模型
2. **安全上下文（Security Context）**：使用标签系统标记所有系统资源
3. **策略引擎**：基于规则的访问控制策略
4. **审计功能**：详细记录访问尝试和拒绝
5. **防御深度**：即使应用程序被攻破，也能限制潜在的损害

### SELinux 运行模式

SELinux 有三种主要的运行模式：

1. **Enforcing（强制模式）**：SELinux 策略被强制执行，违反策略的行为会被拒绝并记录到日志中
2. **Permissive（宽容模式）**：SELinux 策略不被强制执行，但违反策略的行为会被记录到日志中
3. **Disabled（禁用模式）**：SELinux 完全关闭

## 检查 SELinux 状态

### 查看当前 SELinux 状态

```bash
# 查看 SELinux 状态
getenforce

# 查看更详细的 SELinux 状态
seinfo -a

# 查看 SELinux 配置
sestatus
```

### 查看 SELinux 配置文件

SELinux 的主要配置文件是 `/etc/selinux/config`：

```bash
cat /etc/selinux/config
```

典型的配置文件内容：

```
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of these three values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected.
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted
```

## 临时更改 SELinux 模式

### 切换到 Permissive 模式

```bash
sudo setenforce 0
```

### 切换到 Enforcing 模式

```bash
sudo setenforce 1
```

### 验证更改

```bash
getenforce
```

## 永久更改 SELinux 模式

要永久更改 SELinux 模式，需要编辑配置文件：

```bash
sudo vim /etc/selinux/config
```

修改 `SELINUX=` 行：

```
SELINUX=enforcing  # 强制模式
SELINUX=permissive  # 宽容模式
SELINUX=disabled  # 禁用模式
```

修改后需要重启系统才能生效。注意：从 `enforcing` 或 `permissive` 切换到 `disabled` 或反之需要重启系统。

## 安全上下文（Security Context）

### 查看安全上下文

#### 查看文件的安全上下文

```bash
ls -Z filename
ls -laZ directory
```

#### 查看进程的安全上下文

```bash
ps auxZ | grep process_name
```

#### 查看端口的安全上下文

```bash
semanage port -l
netstat -tulpnZ
```

### 安全上下文的组成

安全上下文由四个部分组成，用冒号分隔：

```
user:role:type:level
```

- **user**：用户身份标识（如 unconfined_u, system_u）
- **role**：角色标识（如 object_r, system_r）
- **type**：类型标识，最常用的部分（如 httpd_t, sshd_t, user_home_t）
- **level**：用于 MLS/MCS 策略（可选）

## 管理 SELinux 上下文

### 修改文件的 SELinux 上下文

#### 使用 chcon 命令（临时更改）

```bash
# 复制现有文件的上下文
chcon --reference=source_file target_file

# 手动设置上下文
chcon -t httpd_sys_content_t /var/www/html/file.html

# 递归更改目录上下文
chcon -R -t httpd_sys_content_t /var/www/html/directory/
```

#### 使用 semanage 和 restorecon 命令（永久更改）

```bash
# 添加文件上下文规则
sudo semanage fcontext -a -t httpd_sys_content_t '/var/www/custom(/.*)?'

# 应用上下文规则
sudo restorecon -Rv /var/www/custom
```

### 管理端口上下文

```bash
# 查看端口上下文规则
sudo semanage port -l | grep ssh

# 添加端口上下文规则
sudo semanage port -a -t sshd_port_t -p tcp 2222

# 删除端口上下文规则
sudo semanage port -d -t sshd_port_t -p tcp 2222

# 修改端口上下文规则
sudo semanage port -m -t sshd_port_t -p tcp 2222
```

## SELinux 布尔值（Booleans）

SELinux 布尔值提供了一种灵活的方式来调整 SELinux 策略，而无需修改策略本身。

### 查看 SELinux 布尔值

```bash
# 查看所有布尔值及其状态
sudo getsebool -a

# 查看特定布尔值
sudo getsebool httpd_can_network_connect
```

### 临时修改 SELinux 布尔值

```bash
# 启用布尔值
sudo setsebool httpd_can_network_connect on

# 禁用布尔值
sudo setsebool httpd_can_network_connect off
```

### 永久修改 SELinux 布尔值

使用 `-P` 选项使其永久生效：

```bash
# 永久启用布尔值
sudo setsebool -P httpd_can_network_connect on

# 永久禁用布尔值
sudo setsebool -P httpd_can_network_connect off
```

## SELinux 策略模块

### 查看已安装的策略模块

```bash
sudo semodule -l
```

### 安装和删除策略模块

```bash
# 安装策略模块
sudo semodule -i module.pp

# 删除策略模块
sudo semodule -r module

# 禁用策略模块
sudo semodule -d module

# 启用策略模块
sudo semodule -e module
```

## SELinux 故障排查

### 查看 SELinux 拒绝日志

SELinux 拒绝访问的信息主要记录在 `/var/log/audit/audit.log` 文件中。

```bash
# 查看 SELinux 拒绝信息
sudo grep "AVC: denied" /var/log/audit/audit.log

# 使用 ausearch 过滤拒绝信息
sudo ausearch -m AVC,USER_AVC,SELINUX_ERR -ts recent
```

### 使用 sealert 分析拒绝信息

sealert 工具可以分析 SELinux 拒绝信息并提供解决建议：

```bash
# 安装 setroubleshoot-server
sudo dnf install setroubleshoot-server -y

# 分析拒绝信息并生成建议
sudo sealert -a /var/log/audit/audit.log
```

### 使用 audit2allow 生成策略模块

audit2allow 工具可以从拒绝日志中生成允许访问的 SELinux 策略：

```bash
# 查看建议的策略
sudo grep "httpd" /var/log/audit/audit.log | audit2allow -m httpd_custom

# 生成策略模块文件
sudo grep "httpd" /var/log/audit/audit.log | audit2allow -M httpd_custom

# 安装生成的策略模块
sudo semodule -i httpd_custom.pp
```

## 常见 SELinux 问题及解决方案

### Web 服务器问题

#### Apache 无法访问自定义目录

问题：Apache 无法访问 `/var/www/custom` 目录中的文件。

解决方案：

```bash
# 设置正确的上下文
sudo semanage fcontext -a -t httpd_sys_content_t '/var/www/custom(/.*)?'
sudo restorecon -Rv /var/www/custom

# 允许 Apache 读取用户主目录中的内容（如果需要）
sudo setsebool -P httpd_enable_homedirs on
```

#### Apache 无法连接到数据库

问题：Apache 运行的 PHP 应用无法连接到数据库。

解决方案：

```bash
# 允许 Apache 连接到网络
sudo setsebool -P httpd_can_network_connect_db on
```

### SSH 问题

#### 自定义 SSH 端口无法访问

问题：更改 SSH 端口后无法连接。

解决方案：

```bash
# 添加自定义端口到 SELinux
sudo semanage port -a -t sshd_port_t -p tcp 2222
```

### FTP 问题

#### FTP 服务器无法上传文件

问题：vsftpd 服务器无法上传文件。

解决方案：

```bash
# 允许 FTP 写访问
sudo setsebool -P ftpd_anon_write on
sudo setsebool -P ftpd_write_enable on

# 如果使用本地用户
sudo setsebool -P allow_ftpd_full_access on
sudo setsebool -P allow_ftpd_use_cifs on
sudo setsebool -P allow_ftpd_use_nfs on
```

### Samba 问题

#### Samba 无法访问共享目录

问题：Samba 无法访问或共享目录。

解决方案：

```bash
# 设置正确的上下文
sudo semanage fcontext -a -t samba_share_t '/srv/samba(/.*)?'
sudo restorecon -Rv /srv/samba

# 允许 Samba 共享主目录
sudo setsebool -P samba_enable_home_dirs on

# 允许 Samba 访问 CIFS 和 NFS
sudo setsebool -P samba_use_cifs on
sudo setsebool -P samba_use_nfs on
```

## SELinux 与容器

### Docker 与 SELinux

当使用 Docker 与 SELinux 时，需要特别注意安全上下文的设置。

```bash
# 安装 docker-selinux 包
sudo dnf install docker-selinux -y

# 查看 Docker 相关的 SELinux 布尔值
sudo getsebool -a | grep docker

# 启用 Docker 相关的 SELinux 布尔值
sudo setsebool -P docker_connect_any on
```

### Podman 与 SELinux

Podman 原生支持 SELinux，可以使用卷标签来控制容器对主机文件系统的访问。

```bash
# 使用 Z 选项设置 SELinux 标签
podman run -v /host/dir:/container/dir:Z image_name

# 查看容器的 SELinux 上下文
podman inspect --format '{{.ProcessLabel}}' container_id
```

## SELinux 性能考虑

虽然 SELinux 提供了额外的安全层，但在某些高负载环境中可能会对性能产生一定影响。

### 优化 SELinux 性能

1. **调整审计日志设置**：

```bash
sudo vim /etc/audit/auditd.conf
```

2. **使用审计过滤器**：

```bash
sudo auditctl -w /path/to/file -p rwxa -k my_key
```

3. **考虑使用 targeted 策略**：Rocky Linux 默认使用 targeted 策略，它只对选定的进程应用 SELinux 限制，减少了整体系统开销。

## SELinux 最佳实践

1. **保持 SELinux 处于 enforcing 模式**：在可能的情况下，始终保持 SELinux 处于强制模式以获得最大的安全保护。

2. **使用 permissive 模式进行故障排查**：在排除 SELinux 相关问题时，可以临时切换到 permissive 模式。

3. **使用布尔值而不是完全禁用 SELinux**：当遇到权限问题时，尝试使用 SELinux 布尔值进行调整，而不是直接禁用 SELinux。

4. **定期检查 SELinux 日志**：定期检查 SELinux 拒绝日志，及时发现潜在的安全问题。

5. **为自定义应用程序创建适当的策略**：如果有自定义应用程序，创建适当的 SELinux 策略模块以允许其正常工作。

6. **备份 SELinux 配置**：在进行重大更改前，备份 `/etc/selinux/config` 文件和当前的策略设置。

## 总结

SELinux 是 Rocky Linux 中一个强大的安全机制，它通过强制访问控制提供了超越传统 Linux 权限模型的额外安全层。虽然 SELinux 有时可能会导致配置上的复杂性，但它提供的安全增强是值得的。

本教程介绍了 SELinux 的基本概念、运行模式、安全上下文、布尔值管理以及常见问题的排查方法。通过正确配置和管理 SELinux，您可以显著提高系统的安全性，减少潜在的安全漏洞。

记住，在处理 SELinux 问题时，首先应该尝试理解和解决问题，而不是简单地禁用 SELinux。通过使用本教程中介绍的工具和技术，您应该能够有效地管理 SELinux 并解决大多数相关问题。
