DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

systemd 隐藏了服务用户的家目录:用 ProtectHome=tmpfs 配置窄范围访问

服务账户能在终端访问自己的家目录,systemd 却启动失败时,检查 ProtectHome 的挂载视图,再用 tmpfs 与窄范围只读绑定配置所需路径。

服务以 testuser 启动,工作目录也在 /home/testuser/testdir,交互终端里这个用户能访问文件,systemd 启动却在进入目录或读取程序时失败。若 unit 启用了 ProtectHome=yes,还需要检查服务自己的文件系统视图:它会隐藏 /home、/root 和 /run/user,并不会因为 User 指向 testuser 就自动放行 testuser 的家目录。

以下针对支持相应挂载命名空间设置的 Linux systemd 系统服务。服务还需要其他沙箱或容器层时,各层都可能限制路径;普通用户服务是否能使用这些设置也取决于系统支持,不能仅凭一份配置推断已经生效。

区分目录权限和服务看不见目录

先读取完整 unit、drop-in 和近期日志,核对实际 User、WorkingDirectory、ExecStart 以及路径保护设置。名称是示例:

systemctl cat example.service
systemctl show example.service -p User -p WorkingDirectory -p ProtectHome -p BindReadOnlyPaths
journalctl -u example.service -b -n 80 --no-pager

记录失败发生在进入工作目录、执行程序还是应用读取文件时。如果服务账户在宿主环境也不能穿过目录或读取目标,先解决真实的属主、目录搜索权限和文件权限;增加绑定挂载不会绕过这些访问控制。

如果宿主环境访问正常,而 unit 的 ProtectHome 为 yes,路径在服务中被隐藏就有了具体依据。仍要核对 RootDirectory、RootImage、InaccessiblePaths 及其他挂载设置,因为它们可能同时改变路径可见性。不要把某次升级后的失败直接认定为 systemd 的统一版本回归;配置、程序路径与实际隔离行为都需要确认。

ReadWritePaths 不能把隐藏的家目录重新变出来

ProtectHome 的几种取值作用不同:yes 让受保护目录不可访问;read-only 让它们可见但只读;tmpfs 用只读的临时文件系统遮住这些目录,再允许按需绑定特定路径。

ReadWritePaths,或旧配置中的 ReadWriteDirectories,处理的是可见路径上的读写限制。它不能把 ProtectHome=yes 已经隐藏的目录重新暴露出来。在仍为 yes 的情况下添加 /home/testuser/testdir 的窄范围绑定也存在问题:挂载目标必须存在或能创建,而受保护的不可访问父路径不允许这样做。

如果服务只需要读取这一份程序,可以使用 ProtectHome=tmpfs,再通过 BindReadOnlyPaths 暴露指定目录。其他用户的家目录仍被遮住,不必为了程序启动把全部 home 开放。

只暴露程序目录,写入路径另行配置

备份现有 unit 和所有 drop-in,在服务已有定义上添加范围明确的覆盖。以下片段只展示路径例外,保留原来的 User、ExecStart 和其他必要设置:

[Service]
ProtectHome=tmpfs
BindReadOnlyPaths=/home/testuser/testdir
WorkingDirectory=/home/testuser/testdir

BindReadOnlyPaths 只写一个路径时,源路径和服务中的目标路径相同;挂载仅对这个 unit 的文件系统视图有效。这要求实际 systemd 支持上述选项和命名空间机制,且源路径确实存在。RootDirectory 或 RootImage 启用时,绑定源指向宿主路径,目标则在服务根目录之下,需要按实际目录布局确认。

这个目录在服务中是只读的。应用如果把 SQLite 数据库、缓存、上传文件或日志写在程序目录里,还要修改应用写入位置,否则可能从“找不到程序”变成“只读文件系统”。按业务需要使用独立的数据目录;若采用 StateDirectory,应理解它的目录创建和属主调整规则,避免把已有共享数据目录当作一个无影响的选项直接加入。

只有确实需要在家目录中的指定子目录写入时,才考虑对该子目录使用 BindPaths,并评估服务被入侵后能修改的内容。不要把整个 /home/testuser 都绑定为可写,也不要把 chmod 777 当成路径隔离的修复。若部署可以迁移到家目录之外的专用程序目录,也可以通过调整 WorkingDirectory、ExecStart 和应用配置减少家目录例外,但必须处理完整路径与数据迁移。

重启后检查应用行为和隔离范围

路径挂载属于服务启动时建立的视图。安排维护窗口,确认正在处理的任务及数据已妥善保存,再重新加载 unit 并重启服务:

systemctl daemon-reload
systemctl restart example.service
systemctl status example.service --no-pager

这些管理操作需要相应权限,restart 会中断当前服务。修改后应确认进程使用了预期目录,业务入口可用,必要的读写都落在选定路径;同时确认无关家目录仍没有暴露。只看到进程启动成功,不能证明写入路径和隔离范围都符合要求。

如果仍失败,按新日志区分源路径不存在、传统权限拒绝、只读路径写入、挂载机制不支持或其他隔离设置冲突,针对该层继续处理。回退时恢复备份的 unit 与 drop-in,重新加载并重启,随后复核业务与目录视图。已经写入或迁移的数据需按数据备份单独恢复,配置回退不会撤销这些修改。