我有一个每 5 分钟运行一次的 Golang 二进制文件。它应该创建和更新需要写入限制的文本文件。为了运行这个二进制文件,我创建了一个 systemd 服务和一个 systemd 计时器单元。 Systemd 服务使用 DynamicUser。为了实现访问限制,我CacheDirectory
在 systemd 中使用指令,以便只有 DynamicUser 可以写入该文件,并且它仅在用户存在时存在。还设置CacheDirectoryMode=644
为仅允许具有写入权限的所有者。
当 systemd 服务运行时,它失败并显示
failed to read output file: lstat /var/cache/monitor/output_file.txt: permission denied>
问题:尽管服务单元将创建动态用户并运行创建/更新/读取文件的可执行文件,但为什么在 systemd 服务运行时尝试读取文件时该可执行文件本身会被拒绝?
file-monitor.go 编译生成 /usr/local/bin/file-monitor 二进制文件
package main
import (
"fmt"
"os"
)
function foo() {
var outputFile = os.Getenv("CACHE_DIRECTORY") + "/output_file.txt"
outputFileBytes, err := os.ReadFile(outputFile)
if err != nil {
return fmt.Errorf("failed to read output file %s: %v\n", outputFile, err)
}
}
function main() {
foo()
}
文件更新程序.service
[Unit]
Description="description"
After=file-updater.service
[Service]
DynamicUser=yes
User=monitor
Group=monitor
CacheDirectory=monitor
CacheDirectoryMode=644
ExecStart=/usr/local/bin/file-monitor <arg1>
Type=oneshot
[Install]
WantedBy=multi-user.target
答案1
CacheDirectoryMode=644
这允许读取目录列表。不与此目录列表中的文件交互:需要 eXecute 位来进一步遍历路径并访问目录中的文件。这使得用户具有写权限监视器也无用。
将该参数修改为:
CacheDirectoryMode=755
这是默认值(即:您可以删除此参数)。现在允许访问此目录中的文件,以便用户读取或写入监视器。
该行为链接自系统的文档(RuntimeDirectoryMode=、StateDirectoryMode=、CacheDirectoryMode=、LogsDirectoryMode=、ConfigurationDirectoryMode=)到手册path_resolution(7)
其中包括有关基本 Unix 访问的所有详细信息,尤其是第二步:沿着小路行走并在允许段落:
如果进程没有当前查找目录的搜索权限,返回 EACCES 错误(“权限被拒绝”)。
使用的三位中,第一位决定读权限,第二位决定写权限,并且最后对于普通文件,执行权限,或者目录的搜索权限。