我想使用 systemd 单元文件启动服务。该服务需要密码才能启动。我不想将密码以明文形式存储在 systemd 单元文件中,因为它是世界可读的。我也不想以交互方式提供此密码。
如果我为此编写一个普通脚本,我会将凭据存储在 root 拥有的具有受限权限(400 或 600)的文件中,然后读取该文件作为脚本的一部分。是否有任何特定的 systemd 风格的方法来执行此操作,或者我应该遵循与常规 shell 脚本相同的过程?
答案1
这里有两种可能的方法,具体取决于您的要求。如果你不要如果希望在激活服务时提示输入密码,请使用该EnvironmentFile
指令。从man systemd.exec
:
与Environment=类似,但从文本文件中读取环境变量。文本文件应包含换行符分隔的变量分配。
如果你做如果想要得到提示,您可以使用其中一个systemd-ask-password
指令。从man systemd-ask-password
:
systemd-ask-password 可用于使用命令行上指定的问题消息来查询用户的系统密码或密码。当从 TTY 运行时,它将查询 TTY 上的密码并将其打印到标准输出。当不使用 TTY 或使用 --no-tty 运行时,它将使用系统范围的查询机制,该机制允许活动用户通过多个代理进行响应
答案2
根据 systemd 手册(systemd.exec 等),普通环境变量不应用于凭据管理。 Systemd 有一个完整的手册页描述其选项,例如 LoadCredential、LoadCredentialEncrypted、SetCredential、SetCredentialEncrypted。看https://systemd.io/CREDENTIALS/和 systemd.exec 手册页,了解在 systemd 中执行此操作的正确方法的完整描述。
使用环境变量意味着不需要凭据的进程可能仍会继承或访问这些变量,并且可能会导致秘密无意中泄露。我想要将 systemd 服务与 Bitwarden CLI 集成,并且按照中的说明使用了 SetCredentialEncryptedhttps://systemd.io/CREDENTIALS/。经过几次调整(bw
预计设置 HOME 环境变量)后,我的 Bitwarden 主密码在磁盘上静态加密,只有我的服务部门可以访问它来解锁我的 Bitwarden 帐户。
我就是这样做的。首先,我将 Bitwarden 主密码写入一个常规文件,我们称之为/tmp/bwmaster.pass。回想起来,最好将其写入 ramdisk,而不是 Btrfs,可能会选择/跑步/(所有这些命令都需要 root 访问权限)。接下来,我创建了主密码的加密副本:
# systemd-creds encrypt --pretty --name=bwmp /tmp/bwmaster.pass -
这将漂亮地打印 SetCredentialEncrypted=bwmp 简介,您可以将其添加到 systemd 服务单元文件的 [Service] 部分(直接或作为覆盖)。这是我的输出:
SetCredentialEncrypted=bwmp: \
k6iUCUh0RJCQyvL8k8q1UyAAAAABAAAADAAAABAAAADCNQBSGbmpFUpRgngAAAAAgAAAA \
AAAAAALACMA0AAAACAAAAAAfgAgCE+qUDoEpxT3155oWkncltAG6Wv+IQAEm7EwIhahpw \
gAEB8dLosK741kyXWOWXQwLRfvhx6vDf7Na6JNGNW3PQkF6TZmJsUNYsWGXLgyIbgtjkd \
0TkS0LfVOo/e6PQ32p/xfEj0b+ZGCXgtjC0Tx6sDedhU0fIfT2b+IlwBOAAgACwAAABIA \
ID8H3RbsT7rIBH02CIgm/Gv1ukSXO3DMHmVQkDG0wEciABAAINgs66YvSM+PW+qPTnGE/ \
8Yq67HHaX5XMmymUojmugUkPwfdFuxPusgEfTYIiCb8a/W6RJc7cMweZVCQMbTARyIAAA \
AAWUZXjxS/vfx0BJq8RQAAyeXdSsf7ccsz+yEcMvoUm4WYZupWzt1FW93FDsUpdyi+QID \
pqczUQ24ODMC+HP9vP7nvLHPF4uNk+iPkR5fF7Ypl5rHdcFyfm1Bqp70g
将其存储在我的服务单元文件中后,我安全地删除了临时纯文本文件:
# shred -uz /tmp/bwmaster.pass
man shred
有关这方面的更多详细信息,请参阅。当我这样做时,我使用 Bitwarden 来存储我的 Borg 加密备份凭证。我编写了以下服务文件:
[Unit]
Wants=network.target
After=network-online.target
[Service]
Type=oneshot
SetCredentialEncrypted=bwmp: \
k6iUCUh0RJCQyvL8k8q1UyAAAAABAAAADAAAABAAAADCNQBSGbmpFUpRgngAAAAAgAAAA \
AAAAAALACMA0AAAACAAAAAAfgAgCE+qUDoEpxT3155oWkncltAG6Wv+IQAEm7EwIhahpw \
gAEB8dLosK741kyXWOWXQwLRfvhx6vDf7Na6JNGNW3PQkF6TZmJsUNYsWGXLgyIbgtjkd \
0TkS0LfVOo/e6PQ32p/xfEj0b+ZGCXgtjC0Tx6sDedhU0fIfT2b+IlwBOAAgACwAAABIA \
ID8H3RbsT7rIBH02CIgm/Gv1ukSXO3DMHmVQkDG0wEciABAAINgs66YvSM+PW+qPTnGE/ \
8Yq67HHaX5XMmymUojmugUkPwfdFuxPusgEfTYIiCb8a/W6RJc7cMweZVCQMbTARyIAAA \
AAWUZXjxS/vfx0BJq8RQAAyeXdSsf7ccsz+yEcMvoUm4WYZupWzt1FW93FDsUpdyi+QID \
pqczUQ24ODMC+HP9vP7nvLHPF4uNk+iPkR5fF7Ypl5rHdcFyfm1Bqp70g
Environment=BWMPATH=%d/bwmp
ExecStart=/usr/local/sbin/borg.sh
我的还有一点博格服务文件,但我只包含了本主题的重要部分。根据手册,应该有一个可以在脚本中引用的 $CREDENTIAL_PATH/bwmp 文件,但是直到我像上面那样定义了 BWMPATH 环境变量之后我才能让它工作。这可能是因为bw
命令 (Bitwarden CLI) 工具需要设置 HOME 变量,因此我在脚本中设置了它(只有 root 会运行borg.sh
)。
请参阅 systemd.exec 和https://systemd.io/CREDENTIALS有关其工作原理的详细信息的手册。该systemd-creds
命令将自动使用 TPMv2 芯片(如果您的系统中可用)以及密钥文件。我不确定我的系统是否有 TPMv2 芯片,这是我稍后会探索的内容。
这对我在 Arch Linux、systemd 251.3-1(一周左右没有更新)上有效。如果您使用的是其他版本,则该版本可能不存在。
答案3
除了@jasonwryan 的第二个建议之外,还有第三种替代方案。
摘自 Michael Hampton 在 ServerFault 上的回答 -如何在systemd服务中设置环境变量?这当前的执行此操作的最佳方法是运行
systemctl edit myservice
,这将为您创建一个覆盖文件或让您编辑现有文件。在正常安装中,这将创建一个目录
/etc/systemd/system/myservice.service.d
,并在该目录内创建一个名称以.conf
(通常为override.conf
)结尾的文件,在该文件中,您可以添加或覆盖发行版附带的单元的任何部分。例如,在一个文件中
/etc/systemd/system/myservice.service.d/myenv.conf
:[Service] Environment="SECRET=pGNqduRFkB4K9C2vijOmUDa2kPtUhArN" Environment="ANOTHER_SECRET=JP8YLOc2bsNlrGuD6LVTq7L36obpjzxd"
另请注意,如果该目录存在且为空,您的服务将被禁用!如果您不打算将某些内容放入该目录中,请确保该目录不存在。
答案4
我可以提供可能适合您需求的额外替代方案,但它需要满足几个先决条件:
- 您需要将 systemd 单元设置为用户单元。
- 你需要设置 Gnome 密钥环,我推荐这个方法:https://wiki.archlinux.org/index.php/GNOME/Keyring#PAM_method
接下来的步骤如下:
使用secret-tool
fromlibsecret
来存储您的密码。例如:
$ secret-tool store --label=myProgram myService password
Password: <type it here>
如果您的可执行文件支持从环境变量读取密码,则更好:
[Service]
ExecStart=/usr/bin/sh -c 'env SECRET=$(secret-tool lookup myService password) /usr/bin/script'
如果您的可执行文件接受密码作为参数,您仍然可以secret-tool
像这样使用:
[Service]
ExecStart=/usr/bin/sh -c '/usr/bin/script --secret=$(secret-tool lookup myService password)'
警告:当您运行时,密码将清晰可见,systemctl --user status myUnit.service
因为它显示参数正在命令行上运行。这意味着这对于运行top
或 的用户也可见ps -aux
。