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 的服务需要重点加固。