我的公司在旧版 SLES 上使用 init.d 设置了一些自己开发的软件,使其作为服务运行。我们最近开始在 Amazon EC2 中的 SLES 12 实例上设置新环境,发现 SLES 12 现在使用的是 systemd 而不是 init.d。但是,看起来 init.d 脚本(即 /etc/init.d)中定义的服务仍可正常启动,因为 systemd 在后台执行了一些神奇的操作来处理预先存在的 init.d 脚本,这很棒。
但是我们不想以 root 用户身份运行我们的服务 - 相反,我们创建一个新用户来运行我们的服务。问题是,当我们尝试以非 root 用户身份启动我们的服务时,无论 systemd 为运行旧的 init.d 服务做了什么准备,都会请求 root 身份验证,我们认为这不是必要的。在较旧的 SLES 环境(使用实际的 init.d)上,我们可以毫无困难地以非 root 用户身份启动服务。据我所知,我们的非 root 用户权限和文件所有权在两个环境中是相同的。
我认为这是由于 systemd 在后台处理旧的 init.d 内容造成的,原因是启动我们服务的脚本在实际启动/停止服务命令之前会回显一行文本,但该行不会输出,即我们在回显语句之前被要求进行 root 身份验证。systemd 中隐藏的某个包/模块需要身份验证,但我现在记不起它的名字了。
请注意,如果可能的话,我们希望避免为我们的服务创建特定于服务的 .service 文件 - 我们希望坚持使用我们已有的 init.d 脚本并以非 root 用户身份运行它。此外,我们希望在不使用 sudo 的情况下运行该服务(在旧环境中我们不需要 sudo)。
抱歉,这个问题缺乏具体细节——一旦我回到办公室并能获得具体细节等,我会用更具体的细节来更新它。这似乎是一个常见的问题,所以我希望有人能对此作出解释。
具体来说:我们想以非 root 用户身份在 SLES 12 上使用 systemd 运行使用旧的 init.d 脚本定义的服务。
(更新 1)尝试运行我们的脚本 /etc/init.d/my_service stop 的确切结果是:
/etc/init.d/my_service 停止
重定向到 systemctl stop electrum-gateway-main.service
==== 正在对 org.freedesktop.systemd1.manage-units 进行身份验证 === 需要进行身份验证才能停止“my_service.service”。
身份验证为:root
密码:
当我们尝试停止该服务时,它并未运行,但这与身份验证问题无关。
我对我们的脚本做了更多的挖掘,脚本在要求授权之前到达了以下行:
. /etc/rc.status
问题就出在这里。调用 /etc/rc.status 需要 root 权限吗?
答案1
在 systemd(以及其他现代 init 系统)中,服务启动严格分为两个步骤:
- 用户工具(例如 systemctl)远程要求 init(pid 1)启动特定服务。
- Init 读取服务的配置,设置环境(包括切换到所需的用户帐户),并运行可执行文件。
由于这种间接性,无论谁启动服务、如何启动服务,都可以保证服务始终具有相同的环境。(以前,用户环境(如语言环境、路径或 SELinux 上下文)泄漏到服务中是一个常见问题。)
(对于 init.d 脚本,发行版的 lsb-functions 文件包含到“systemctl start”的魔术重定向,因此它们也接收相同的间接。)
这也意味着你不能“以同一用户身份”启动服务——你必须在相关的 systemd .service 文件中配置一个特定的用户名(如果没有,你确实应该写一个)。
“启动服务”调用通常是有特权的,但您可以编写一个 polkit 规则,允许每个用户或每个服务执行该调用(如果 systemd 版本足够新):
/* /etc/polkit-1/rules.d/allow-whatever.rules */
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units") {
var verb = action.lookup("verb");
var unit = action.lookup("unit");
if (subject.user == "manager"
&& unit == "app.service"
&& (verb == "start" || verb == "stop" || verb == "restart"))
{
return polkit.Result.YES;
}
}
});
或者,可能可以选择退出 init.d 脚本中的间接寻址,但这样您也会完全失去 systemd 的服务跟踪——您的守护进程看起来就像一个常规的用户进程。
答案2
以非 root 用户身份运行服务是个好主意。除了另一个答案中的 Polkit 建议外,还有几种更常规的方法可以不以 root 身份启动服务:
- 使用 sudo。sudo 规则可以允许特定用户运行特定服务的
start
和restart
命令,但不以 root 身份执行任何操作,从而提供相同类型的有限权限。 - 使用 systemd
user
模式.systemd 为用户提供了通过每个用户的 systemd 实例来管理用户控制下的服务的能力,使用户能够启动、停止、启用和禁用他们自己的单元。
我认为 systemd 用户模式可能更多地适用于桌面用例。对于服务器,我建议允许使用该sudo
解决方案。在 systemd.service
文件中,您还可以设置User=
指令来指定服务以哪个用户身份运行——可能与您能够启动该服务的用户相同。
“polkit” 解决方案是一种远程操作解决方案——似乎很难理解是什么让用户启动了该服务。但是,使用 时,sudo
您显然是在调用sudo
,而使用 时systemd user mode
,您显然是在使用该功能。
如果我处于设置了 Polkit 解决方案的环境中,除非同事留下一些相关文档,否则我将无法查明启动该服务为何能够正常工作。