使用 RootDirectory= 运行 systemd 服务并访问 /bin 二进制文件

使用 RootDirectory= 运行 systemd 服务并访问 /bin 二进制文件

我正在尝试利用一些 systemd 助手来chroot(2)该过程使用RootDirectory=.它是一个基本的 Python 脚本,位于/srv/http托管 Web 服务器的下方。它有一个舍邦#!/usr/bin/python (我也尝试过不同的组合)

服务文件也很简单:

[Unit]
Wants=network-online.target
After=network-online.target

AssertPathExists=/srv/http

[Service]
Type=simple
Restart=always
RestartSec=10

RootDirectory=/srv/http
PrivateTmp=true

ExecStart=/server.py
PIDFile=/run/miniweb.pid

[Install]
WantedBy=multi-user.target

日志清楚地表明它找不到可执行文件:

Mar 11 19:23:49 bigrigv2 systemd[13213]: testweb.service: Failed to execute /server.py: No such file or directory
Mar 11 19:23:49 bigrigv2 systemd[13213]: testweb.service: Failed at step EXEC spawning /server.py: No such file or directory

它被标记为可执行:

-rwxr-xr-x 1 anton anton  650 Mar 11 19:06 server.py

我还尝试了ExecStart=/bin/python /srv/http/server.py其他变化。我不完全确定我是否理解概念RootDirectory以及如何从 chroot 服务脚本中正确执行 Python 或其他二进制文件。我的假设是,在执行服务之前,它会 chroot:s 进入,/srv/http之后在这种情况下服务将无法退出并执行 Python。这是有道理的,但我不太明白为什么/server.py没有找到。您将如何执行依赖于其他二进制文件的事情?大多数解决方案都提到利用该语言(例如 C)chroot并从应用程序控制它,但我不明白在服务脚本中为除非常有限的 bash 脚本或独立二进制文件之外的其他内容提供 chroot 的意义。

可能是一个非常简单的问题,但我很迷失,任何帮助将不胜感激!

答案1

直接回答你的问题:

如何使用 RootDirectory 在 chroot 之外正确执行具有外部依赖项的服务。

你不能。如果某些内容位于 chroot 监狱中,则它无法访问外部的任何内容,包括二进制文件和库。但您仍然有方法可以保护您的系统。

man systemd.exec

采用相对于主机根目录(即运行服务管理器的系统的根目录)的目录路径。使用 chroot(2) 系统调用设置已执行进程的根目录。如果使用这个,必须确保进程二进制文件及其所有辅助文件在 chroot() 监狱中可用

如果您设置了RootDirectory=/srv/http,那么当/server.py被调用时,它将尝试执行/usr/bin/python,但会失败,因为它找不到该路径。即使您可以执行类似的操作,当您尝试这样做或因为这些库未安装在您的 chroot 中时,ExecStartPre=/bin/cp /usr/bin/python /src/http/usr/bin/python您仍然会遇到问题。我用像你这样的设置做了一个测试,没有一个好的 shebang,我得到了和你一样的错误。import flaskimport pyramid

这里有三个选项:

  1. 为您的 chroot 提供所需的一切。如果您使用的是基于 Debian 的系统,那么debootstrap是一个很好的工具来设置它deboostrap buster /srv/http应该可以工作。它将安装一个基本系统,然后您可以sudo chroot && apt install python python-flask在里面安装任何您喜欢的东西。

  2. 使用内置选项对您的服务进行沙箱处理,而不是对其进行 chroot。具体来说:

  • RemoveIPC=truePrivateTmp=true。这些确保由执行的进程创建的 IPC 对象和临时文件的生命周期与服务的运行时绑定。由于/tmp/var/tmp通常是系统上唯一的世界可写目录,这确保了单元在终止后不会留下文件。
  • NoNewPrivileges=trueRestrictSUIDSGID=true。这些确保调用的进程无法受益或创建 SUID/SGID 文件或目录。
  • ProtectSystem=strictProtectHome=read-only禁止服务写入文件系统中的任何位置(例外情况是/dev/ /proc//sys/。为了允许服务写入某些目录,必须使用ReadWritePaths=.
  • RuntimeDirectory=为服务分配一个运行时目录,该目录由服务的用户拥有,并在系统终止时自动删除。
  1. 您可以用一行替换我在第二步中所说的所有内容DynamicUser=true。有一个好的开发者的解释在这里

不管怎样,如果你没有使用User=或者DynamicUser=你应该使用。这将阻止您的服务具有对或其他机密的root读取权限。/etc/shadow

我真的很喜欢选项 3。启用它确实可以保护您的系统免受服务的影响。

相关内容