如何通过 systemd 配置 ProtectHome 限制服务访问用户目录

文章导读
在 systemd 服务单元文件的 [Service] 段添加 ProtectHome=yes 或 ProtectHome=read-only,即可限制服务进程访问 /home、/root 和 /run/user 目录。该配置适用于不需要读取用户家目录数据的后台服务,能有效防止凭据窃取和横向渗透。
📋 目录
  1. A 命令速用版
  2. B 为什么会这样
  3. C 分步处理
  4. D 怎么验证是否生效
  5. E 常见坑
  6. F 常见问题
  7. G 参考来源
A A

在 systemd 服务单元文件的 [Service] 段添加 ProtectHome=yes 或 ProtectHome=read-only,即可限制服务进程访问 /home、/root 和 /run/user 目录。该配置适用于不需要读取用户家目录数据的后台服务,能有效防止凭据窃取和横向渗透。

先说结论:ProtectHome 是 systemd 内置的沙箱选项,通过挂载命名空间隔离用户家目录,无需额外脚本即可生效。

  • 适合:对外暴露的网络服务、数据库、Web 应用等不需要访问用户个人配置的场景
  • 优先做:先确认服务是否依赖 /home 下的配置文件或 SSH 密钥,避免启动失败
  • 再验证:使用 systemctl status 和 findmnt 命令检查挂载属性是否包含 ro 或不可见

命令速用版

若需快速为现有服务添加保护,可使用 systemctl edit 创建覆盖配置,无需直接修改原文件。

systemctl edit myservice.service
# 在编辑器中输入以下内容
[Service]
ProtectHome=read-only

保存退出后重载配置并重启服务。

systemctl daemon-reload
systemctl restart myservice.service

为什么会这样

ProtectHome 通过 mount namespace 机制将特定目录以只读或不可见方式重新挂载,进程视角下无法写入或查看。

systemd 启动服务时会创建独立的挂载命名空间,根据配置将 /home、/root、/run/user 绑定挂载为只读或 tmpfs 空目录。即使服务以 root 身份运行,也无法绕过该限制修改家目录文件,从而阻断攻击者利用服务漏洞窃取用户 SSH 密钥或配置文件的路径。

分步处理

按以下步骤配置并确保服务正常运行。

步骤 1:确认服务依赖

检查服务是否需要从 /home 读取配置或密钥。若服务账号为专用系统账号(如 www-data、postgres),通常不需要访问 /home;若服务需加载用户 SSH 密钥,则不能开启此选项。

步骤 2:编辑单元文件

使用编辑器打开服务配置,或在 /etc/systemd/system/ 下创建覆盖文件。在 [Service] 段添加:

[Service]
ProtectHome=read-only

若需完全不可见,使用 ProtectHome=yes。

步骤 3:重载并重启

执行 daemon-reload 使配置生效,随后重启服务。

systemctl daemon-reload
systemctl restart myservice.service

步骤 4:观察启动状态

如何通过 systemd 配置 ProtectHome 限制服务访问用户目录

检查服务是否因权限问题启动失败,若失败需检查日志中是否有 Permission denied 报错。

怎么验证是否生效

通过查看挂载信息和尝试访问目录来确认隔离效果。

检查挂载属性

使用 findmnt 命令查看服务进程命名空间内的挂载情况,目标目录应显示为只读(ro)。

findmnt -l | grep -E "/home|/root|/run/user"

验证访问权限

进入服务进程命名空间尝试写入文件,应被拒绝。

systemd-run `--scope` `--same-dir` `--shell`
touch /home/testfile
# 应返回 Permission denied

查看服务状态

使用 systemctl show 查看当前激活的保护选项。

systemctl show myservice.service | grep ProtectHome

常见坑

  • 服务启动失败:若应用硬编码依赖 /home/username/.config 路径,开启 ProtectHome 会导致找不到配置。需改用 ReadWritePaths 显式授权或迁移配置路径。
  • 选项值混淆:ProtectHome=true 在不同版本 systemd 中行为可能不一致,建议明确使用 yes 或 read-only。
  • 与 DynamicUser 冲突:若同时启用 DynamicUser=yes,systemd 会自动启用部分保护,需检查是否有配置冲突。
  • 日志写入受阻:若服务试图将日志写入家目录下的文件,会被拦截。应配置日志写入 /var/log。

常见问题

ProtectHome=yes 和 read-only 有什么区别

yes 会将目录完全隐藏不可见,read-only 允许读取但禁止写入。

若服务不需要读取家目录任何内容,使用 yes 更安全;若需读取配置文件但不修改,使用 read-only。

配置后服务无法启动怎么办

通常是因为服务需要写入家目录或被隐藏的路径。

检查 journalctl -u 服务名 日志,找到被拒绝的路径,使用 ReadWritePaths 显式开放该特定目录或修改应用配置。

该配置会影响 root 用户吗

会影响,ProtectHome 对 root 运行的服务同样生效。

这是基于命名空间的隔离,即使进程 UID 为 0,在挂载命名空间内也无法绕过只读限制。

参考来源

  • Linux 系统特定服务账号的 Home 目录禁锢权限配置
  • Systemd 服务沙箱化隔离及文件系统只读配置
  • 怎么利用 Systemd 服务沙箱化功能实现文件系统只读配置
  • systemd 服务锁定:禁止服务修改与系统保护
  • 如何配置服务器进程权限沙箱化部署