我正在尝试利用一些 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 监狱中,则它无法访问外部的任何内容,包括二进制文件和库。但您仍然有方法可以保护您的系统。
采用相对于主机根目录(即运行服务管理器的系统的根目录)的目录路径。使用 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 flask
import pyramid
这里有三个选项:
为您的 chroot 提供所需的一切。如果您使用的是基于 Debian 的系统,那么
debootstrap
是一个很好的工具来设置它deboostrap buster /srv/http
应该可以工作。它将安装一个基本系统,然后您可以sudo chroot && apt install python python-flask
在里面安装任何您喜欢的东西。使用内置选项对您的服务进行沙箱处理,而不是对其进行 chroot。具体来说:
RemoveIPC=true
和PrivateTmp=true
。这些确保由执行的进程创建的 IPC 对象和临时文件的生命周期与服务的运行时绑定。由于/tmp
和/var/tmp
通常是系统上唯一的世界可写目录,这确保了单元在终止后不会留下文件。NoNewPrivileges=true
和RestrictSUIDSGID=true
。这些确保调用的进程无法受益或创建 SUID/SGID 文件或目录。ProtectSystem=strict
并ProtectHome=read-only
禁止服务写入文件系统中的任何位置(例外情况是/dev/
/proc/
和/sys/
。为了允许服务写入某些目录,必须使用ReadWritePaths=
.RuntimeDirectory=
为服务分配一个运行时目录,该目录由服务的用户拥有,并在系统终止时自动删除。
- 您可以用一行替换我在第二步中所说的所有内容
DynamicUser=true
。有一个好的开发者的解释在这里
不管怎样,如果你没有使用User=
或者DynamicUser=
你应该使用。这将阻止您的服务具有对或其他机密的root
读取权限。/etc/shadow
我真的很喜欢选项 3。启用它确实可以保护您的系统免受服务的影响。