systemd 教程 / 安全沙箱(Security Sandboxing)
安全沙箱(Security Sandboxing)
systemd 提供了强大的安全沙箱机制,通过在 Unit 文件中设置各类保护参数,可以有效地限制服务进程的权限,减少攻击面。即使服务被攻破,攻击者也难以在系统中横向移动。
1. 安全沙箱参数总览
以下是 systemd 提供的主要安全沙箱参数分类:
| 分类 | 参数 | 作用 |
|---|---|---|
| 文件系统保护 | ProtectSystem | 保护系统目录只读 |
ProtectHome | 保护用户主目录 | |
ReadWritePaths | 指定可写路径 | |
ReadOnlyPaths | 指定只读路径 | |
| 隔离 | PrivateTmp | 独立的 /tmp 目录 |
PrivateDevices | 隔离设备文件 | |
PrivateNetwork | 隔离网络 | |
PrivateUsers | 隔离用户命名空间 | |
| 权限控制 | NoNewPrivileges | 禁止提权 |
CapabilityBoundingSet | 限制 Linux Capabilities | |
SystemCallFilter | 系统调用过滤 | |
| 网络限制 | RestrictAddressFamilies | 限制可用的 socket 地址族 |
RestrictNamespaces | 限制命名空间类型 | |
| SELinux/AppArmor | SELinuxContext | 设置 SELinux 上下文 |
AppArmorProfile | 指定 AppArmor 配置文件 |
2. 文件系统保护
2.1 ProtectSystem
ProtectSystem 用于保护系统关键目录:
[Service]
ProtectSystem=strict # 最严格:/usr, /boot, /efi, /etc 完全只读
ProtectSystem=full # 中等:/usr, /boot, /efi 只读,/etc 仍可写
ProtectSystem=true # 同 full
级别对比:
| 级别 | /usr | /boot | /efi | /etc |
|---|---|---|---|---|
strict | 只读 | 只读 | 只读 | 只读 |
full | 只读 | 只读 | 只读 | 可写 |
true | 只读 | 只读 | 只读 | 可写 |
2.2 ProtectHome
[Service]
ProtectHome=true # /home, /root, /run/user 完全不可见
ProtectHome=tmpfs # 使用 tmpfs 伪装,进程看到的是空目录
ProtectHome=read-only # 只读挂载
2.3 ReadWritePaths / ReadOnlyPaths
当 ProtectSystem=strict 时,某些路径需要例外:
[Service]
ProtectSystem=strict
ReadWritePaths=/var/lib/myapp /var/log/myapp
ReadOnlyPaths=/etc/myapp
⚠️ 注意:路径支持通配符,如 /var/lib/*,但不支持递归通配。
3. 环境隔离
3.1 PrivateTmp
为服务提供独立的 /tmp 和 /var/tmp:
[Service]
PrivateTmp=true
服务进程看到的 /tmp 实际位于 /tmp/systemd-private-<uuid>-<service>.service-<pid>/tmp。
💡 提示:几乎所有面向网络的服务都应启用 PrivateTmp,防止临时文件竞态攻击。
3.2 PrivateDevices
隔离设备文件,服务只能访问 /dev/null, /dev/zero, /dev/random 等基础设备:
[Service]
PrivateDevices=true
3.3 PrivateNetwork
完全隔离网络,服务无法访问任何网络:
[Service]
PrivateNetwork=true
⚠️ 注意:启用后服务无法绑定端口或发起网络连接,仅适用于纯本地服务。
3.4 PrivateUsers
隔离用户和组命名空间:
[Service]
PrivateUsers=true
进程内部看到的 UID/GID 映射与宿主不同,有效防止提权攻击。
4. 权限控制
4.1 NoNewPrivileges
禁止进程获得新权限(如 setuid、setgid):
[Service]
NoNewPrivileges=true
这是安全加固的基础选项,几乎所有服务都应启用。
4.2 CapabilityBoundingSet
精确控制服务可以使用的 Linux Capabilities:
[Service]
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_DAC_READ_SEARCH
常用 Capabilities:
| Capability | 说明 |
|---|---|
CAP_NET_BIND_SERVICE | 绑定 < 1024 端口 |
CAP_NET_RAW | 使用原始套接字 |
CAP_SYS_ADMIN | 系统管理操作(危险) |
CAP_DAC_READ_SEARCH | 绕过文件读权限检查 |
CAP_CHOWN | 修改文件所有者 |
⚠️ 注意:CAP_SYS_ADMIN 权限范围极大,应尽量避免授予。
4.3 SystemCallFilter
限制服务可以调用的系统调用:
[Service]
# 白名单模式:仅允许列出的系统调用
SystemCallFilter=@system-service
# 黑名单模式:禁止列出的系统调用
SystemCallFilter=~@mount @reboot @swap
预定义组:
| 组名 | 包含的系统调用 |
|---|---|
@system-service | 常规服务所需的系统调用 |
@file-system | 文件系统操作 |
@network-io | 网络 I/O |
@process | 进程管理 |
@mount | 挂载操作 |
@reboot | 重启/关机 |
@swap | 交换空间操作 |
5. 网络限制
5.1 RestrictAddressFamilies
限制服务可以使用的 socket 地址族:
[Service]
RestrictAddressFamilies=AF_INET AF_INET AF_UNIX
常用地址族:
| 地址族 | 说明 |
|---|---|
AF_INET | IPv4 |
AF_INET6 | IPv6 |
AF_UNIX | Unix 域套接字 |
AF_NETLINK | Netlink 套接字 |
5.2 RestrictNamespaces
限制服务可以创建的命名空间类型:
[Service]
RestrictNamespaces=user mnt net ionic
6. SELinux / AppArmor 集成
6.1 SELinux
[Service]
SELinuxContext=system_u:system_r:myapp_t:s0
需要配合 SELinux 策略模块使用。
6.2 AppArmor
[Service]
AppArmorProfile=myapp
对应的 AppArmor 配置文件位于 /etc/apparmor.d/myapp。
7. Seccomp 过滤
systemd 支持通过 SystemCallFilter 使用 BPF 进行 seccomp 过滤:
[Service]
SystemCallFilter=@system-service
SystemCallArchitectures=native # 仅允许原生架构系统调用
MemoryDenyWriteExecute=true # 禁止 W+X 内存映射
LockPersonality=true # 锁定执行域
8. 实际案例
8.1 加固 Nginx 服务
# /etc/systemd/system/nginx.service.d/security.conf
[Service]
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
NoNewPrivileges=true
ReadWritePaths=/var/log/nginx /var/lib/nginx /run
ReadOnlyPaths=/etc/nginx
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_DAC_READ_SEARCH
SystemCallFilter=@system-service @network-io @file-system
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=true
RestrictSUIDSGID=true
RestrictRealtime=true
8.2 加固 Redis 服务
[Service]
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
NoNewPrivileges=true
ReadWritePaths=/var/lib/redis /var/log/redis /run/redis
CapabilityBoundingSet=
SystemCallFilter=@system-service @network-io @file-system
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
8.3 加固 Docker 服务
[Service]
ProtectHome=read-only
PrivateTmp=true
NoNewPrivileges=true
ReadWritePaths=/var/lib/docker /var/run/docker.sock
ReadOnlyPaths=/etc/docker
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_NET_ADMIN
SystemCallFilter=@system-service @mount @file-system
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK
9. 安全加固清单
以下是一份服务安全加固检查清单:
| 检查项 | 推荐值 | 说明 |
|---|---|---|
ProtectSystem | strict | 保护系统目录 |
ProtectHome | true | 隐藏主目录 |
PrivateTmp | true | 隔离临时目录 |
PrivateDevices | true | 隔离设备文件 |
NoNewPrivileges | true | 禁止提权 |
CapabilityBoundingSet | 最小化 | 仅授予必要 capabilities |
SystemCallFilter | 白名单 | 使用 @system-service |
RestrictAddressFamilies | 最小化 | 仅允许需要的地址族 |
RestrictNamespaces | true | 限制命名空间 |
RestrictSUIDSGID | true | 限制 SUID/SGID |
RestrictRealtime | true | 限制实时调度 |
MemoryDenyWriteExecute | true | 禁止 W+X 内存 |
LockPersonality | true | 锁定执行域 |
SystemCallArchitectures | native | 限制系统调用架构 |
10. 验证安全配置
使用 systemd-analyze security 评估服务安全等级:
# 查看服务安全评分
systemd-analyze security nginx.service
# 输出示例(评分 0-10,越低越安全)
# Overall exposure level for nginx.service: 1.8 OK 🙂
💡 提示:目标是将评分控制在 2.0 以下。评分 > 5.0 的服务需要重点加固。