systemd沙箱化通过readonlypaths、protectsystem、protecthome等指令实现进程级只读保护,基于mount namespace与ms_rdonly机制,root亦不可绕过;protectsystem=strict保护/usr、/boot、/etc,protecthome=read-only保护/home等路径。

Systemd 的沙箱化功能可以通过 ReadOnlyPaths、ProtectSystem、ProtectHome 等指令,对服务运行时的文件系统访问施加严格限制,实现运行时只读保护。这不是简单挂载为只读,而是通过命名空间和内核机制(如 mount namespaces + MS_BIND + MS_RDONLY)在进程视角下屏蔽写入能力,即使 root 也无法绕过。
启用基础只读保护:ProtectSystem 和 ProtectHome
这两个是快速启用的高安全基线配置:
-
ProtectSystem=strict:将/usr、/boot、/etc全部以只读方式 bind-mount 到服务的 mount namespace 中;设为full还会额外保护/sys和/proc(部分只读),strict更常用且兼容性更好 -
ProtectHome=read-only:把/home、/root、/run/user设为只读;若设为yes则直接隐藏(不可见)
示例片段:
ProtectSystem=strict ProtectHome=read-only
精细控制只读路径:ReadOnlyPaths 和 ReadOnlyDirectories
当需要更精确地锁定特定目录(比如应用数据目录或配置目录)时使用:
-
ReadOnlyPaths=/var/lib/myapp /etc/myapp.conf:对多个路径同时设为只读;路径必须存在,否则启动失败(可配合RuntimeDirectory=预创建) -
ReadOnlyDirectories=与ReadOnlyPaths行为一致,语义上更强调“目录”,但实际无区别;推荐统一用ReadOnlyPaths - 注意:只读的是路径本身及其所有子内容;若需允许某子路径可写,得用
ReadWritePaths=显式豁免(见下文)
允许例外写入:ReadWritePaths 与 TemporaryFileSystem
完全只读通常不现实,需有选择地开放写权限:
-
ReadWritePaths=/var/lib/myapp/cache /run/myapp:覆盖ReadOnlyPaths或ProtectSystem的限制,仅对列出路径开放写入 -
TemporaryFileSystem=/tmp:rw或/var/run:mode=0755:在服务 mount namespace 中挂载临时内存文件系统(tmpfs),替代真实磁盘路径;比ReadWritePaths更安全,因为重启即清空 - 常见组合:
ProtectSystem=strict+ReadWritePaths=/var/lib/myapp/state+TemporaryFileSystem=/tmp
验证与调试技巧
配置后务必验证是否生效:
- 启动服务后执行:
systemctl status myapp.service查看是否报 mount 相关错误 - 进入服务进程命名空间:
systemd-run --scope --scope --same-dir --shell,再用findmnt | grep myapp观察挂载属性(应含ro) - 测试写入:
systemd-run --scope --unit=test-write --wait -- bash -c 'echo test > /etc/passwd 2>&1',预期返回 “Permission denied” - 日志中留意
Failed at step ... spawning类错误,多因路径不存在或权限冲突导致










