服务安全加固选项
systemd 在单元文件里提供了一套免 SELinux 的沙箱开关,用来按最小权限原则约束服务:能看哪些目录、能不能写文件系统、能不能改内核参数、能不能创建 SUID 文件。这些约束由内核机制执行,配置成本低、见效直接。原则是逐项加、每加一项做一次回归,因为过紧的约束会让服务因路径只读或缺设备而启动失败。
基本信息
| 用途 | 收紧服务可访问的目录、能力与内核接口 |
|---|---|
| 语法 | 在 [Service] 段写 Protect* / Private* / Restrict* / NoNewPrivileges 等指令 |
| 所属 | systemd(systemd.exec 手册定义这些指令) |
| 验证方式 | systemctl show 查看生效值,systemd-analyze security 查看整体暴露面评分 |
典型使用场景
- 自研服务加固:给业务进程套上只读根目录与私有临时目录
- 等保与合规整改:需要给出服务级最小权限的具体落地手段
- 缩小事故半径:即使进程被攻破,能写、能读的范围也已被严格限制
- 第三方组件收口:把不受信任的组件放进更严格的沙箱运行
- 排查权限漂移:确认线上服务的实际暴露面与设计一致
渐进加固示例
渐进加固示例
[Service]
NoNewPrivileges=true # 禁止通过 SUID 提权
PrivateTmp=true # 独立的 /tmp 与 /var/tmp
PrivateDevices=true # 只能看到必要的设备节点
ProtectSystem=strict # 除白名单外整个文件系统只读
ProtectHome=true # 不可访问家目录
ReadWritePaths=/var/lib/myapp /var/log/myapp /run/myapp
ProtectKernelTunables=true # 不可修改内核参数
ProtectKernelModules=true # 不可加载内核模块
RestrictSUIDSGID=true # 不能创建 SUID/SGID 文件验证与打分
验证与打分
systemctl daemon-reload && systemctl restart myapp
systemctl show myapp -p ProtectSystem -p PrivateTmp -p NoNewPrivileges
systemd-analyze security myapp # 看暴露面评分与逐项建议
journalctl -u myapp -n 50 --no-pager # 启动失败时从这里看是哪项约束太紧加固选项对照
| 选项 | 限制内容 | 风险与注意 |
|---|---|---|
| ProtectSystem=strict | 除 ReadWritePaths 外整个文件系统只读 | 路径没列全会导致写入失败 |
| ProtectSystem=full | 系统目录与配置文件只读,其余可写 | 比 strict 宽松,兼容性更好 |
| ProtectHome=true | 家目录不可访问 | 需要家目录数据的服务不能开 |
| PrivateTmp=true | 独立临时目录空间 | 与外部进程共享临时文件的服务不兼容 |
| PrivateDevices=true | 只暴露必要的设备节点 | 需要访问特定设备的服务要额外放行 |
| NoNewPrivileges=true | 禁止任何形式的提权 | 几乎无副作用,优先开启 |
| RestrictSUIDSGID=true | 禁止创建 SUID/SGID 文件 | 极少服务需要创建这类文件 |
systemd-analyze security 会给单元打一个暴露面评分并逐项列出建议,适合作为加固进度的量化参考。评分不是越高越好,关键在于每一项是否与服务的真实需求匹配。
加固选项可能让服务因路径只读或缺设备直接启动失败。每次只加一两项并回归验证,确认业务正常后再继续。启动失败时先看 journal,错误里通常会指明被拒绝的系统调用或路径。