无法在服务启动时运行 sudo (但仅限于脚本中)

无法在服务启动时运行 sudo (但仅限于脚本中)

在服务启动期间尝试安装外部 USB 驱动器的脚本出现错误:

sudo:有效 uid 不为 0,/usr/bin/sudo 是否位于设置了“nosuid”选项的文件系统上或没有 root 权限的 NFS 文件系统上?

(请注意,挂载操作必须是同步的,因此将其放在服务之外的其他位置ExecStartPre是不够的。挂载必须是成功服务启动的硬依赖项。规则:如果挂载因任何原因失败,则服务不会稍后我将开始处理通知。)

这是我的服务配置,在用户上下文中运行admin

### Editing /etc/systemd/system/[email protected]/override.conf
### Anything between here and the comment below will become the new contents of the file

[Service]
ExecStartPre=/usr/local/bin/mount-sync-drive.sh

### Lines below this comment will be discarded

### /lib/systemd/system/[email protected]
# [Unit]
# Description=Syncthing - Open Source Continuous File Synchronization for %I
# Documentation=man:syncthing(1)
# After=network.target
# StartLimitIntervalSec=60
# StartLimitBurst=4
#
# [Service]
# User=%i
# ExecStart=/usr/bin/syncthing serve --no-browser --no-restart --logflags=0 --home=/media/pi/MyBook/.config/syncthing
# Restart=on-failure
# RestartSec=1
# SuccessExitStatus=3 4
# RestartForceExitStatus=3 4
#
# # Hardening
# ProtectSystem=full
# PrivateTmp=true
# SystemCallArchitectures=native
# MemoryDenyWriteExecute=true
# NoNewPrivileges=true
#
# # Elevated permissions to sync ownership (disabled by default),
# # see https://docs.syncthing.net/advanced/folder-sync-ownership
# #AmbientCapabilities=CAP_CHOWN CAP_FOWNER
#
# [Install]
# WantedBy=multi-user.target

...和我的脚本:

#!/bin/bash

exec &>> /var/log/syncthing.log
echo ""
date

# Check if /dev/sda1 is already mounted
if ! grep -qs '/dev/sda1' /proc/mounts; then
    # Mount /dev/sda1 to /media/pi/MyBook
    echo "Mounting /dev/sda1 to /media/pi/MyBook"
    sudo mount -v /dev/sda1 /media/pi/MyBook
fi

当我手动运行脚本时admin,驱动器安装得很好:

pi@RPI:~ $ mount | grep sda1
pi@RPI:~ $ sudo -u admin /usr/local/bin/mount-sync-drive.sh
mount: /dev/sda1 mounted on /media/pi/MyBook.
pi@RPI:~ $ mount | grep sda1
/dev/sda1 on /media/pi/MyBook type ext4 (rw,relatime)

以下是 的内容syncthing.log

Wed 22 Feb 15:57:43 AKST 2023
Mounting /dev/sda1 to /media/pi/MyBook
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?

Wed 22 Feb 15:57:44 AKST 2023
Mounting /dev/sda1 to /media/pi/MyBook
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?

Wed 22 Feb 15:57:45 AKST 2023
Mounting /dev/sda1 to /media/pi/MyBook
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?

Wed 22 Feb 15:57:46 AKST 2023
Mounting /dev/sda1 to /media/pi/MyBook
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?

这是服务启动错误(journalctl没有透露更多信息):

pi@RPI:~ $ sudo systemctl status [email protected][email protected] - Syncthing - Open Source Continuous File Synchronization for admin
     Loaded: loaded (/lib/systemd/system/[email protected]; enabled; vendor preset: enabled)
    Drop-In: /etc/systemd/system/[email protected]
             └─override.conf
     Active: failed (Result: exit-code) since Tue 2023-02-21 17:23:14 AKST; 33s ago
       Docs: man:syncthing(1)
    Process: 959 ExecStartPre=/usr/local/bin/mount-sync-drive.sh (code=exited, status=1/FAILURE)
        CPU: 53ms

Feb 21 17:23:14 RPI systemd[1]: [email protected]: Scheduled restart job, restart counter is at 4.
Feb 21 17:23:14 RPI systemd[1]: Stopped Syncthing - Open Source Continuous File Synchronization for admin.
Feb 21 17:23:14 RPI systemd[1]: [email protected]: Start request repeated too quickly.
Feb 21 17:23:14 RPI systemd[1]: [email protected]: Failed with result 'exit-code'.
Feb 21 17:23:14 RPI systemd[1]: Failed to start Syncthing - Open Source Continuous File Synchronization for admin.

如果我错了,请纠正我,但我相信我已经排除了mount错误消息中指出的所有可能性:

1. 文件系统上的 /usr/bin/sudo 设置了 'nosuid' 选项:

pi@RPI:~ $ mount | grep nosuid
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,size=186292k,nr_inodes=819200,mode=755)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot)
pstore on /sys/fs/pstore type pstore (rw,nosuid,nodev,noexec,relatime)
bpf on /sys/fs/bpf type bpf (rw,nosuid,nodev,noexec,relatime,mode=700)
mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime)
tracefs on /sys/kernel/tracing type tracefs (rw,nosuid,nodev,noexec,relatime)
debugfs on /sys/kernel/debug type debugfs (rw,nosuid,nodev,noexec,relatime)
fusectl on /sys/fs/fuse/connections type fusectl (rw,nosuid,nodev,noexec,relatime)
configfs on /sys/kernel/config type configfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,size=93144k,nr_inodes=23286,mode=700,uid=1000,gid=1000)

2. 是具有 NFS 文件系统且没有 root 权限的文件系统上的 /usr/bin/sudo:

pi@RPI:~ $ df -T /usr/bin/sudo
Filesystem     Type 1K-blocks    Used Available Use% Mounted on
/dev/root      ext4  30343244 4241732  24811444  15% /

我已admin使用以下命令添加到 sudoers 文件visudo并重新启动:

admin ALL=(ALL) NOPASSWD: /bin/mount

非常奇怪的是我有另一个类似的系统运行得很好。我已经检查并仔细检查了所有配置,它们是相同的。

这是什么意思,sudo: effective uid is not 0以及如何解决它?

- 编辑 -

@ajgringo619根据评论中的问题:

pi@RPI:~ $ sudo -lU admin
Matching Defaults entries for admin on RPI:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, env_keep+=NO_AT_BRIDGE, env_keep+="http_proxy
    HTTP_PROXY", env_keep+="https_proxy HTTPS_PROXY", env_keep+="ftp_proxy FTP_PROXY", env_keep+=RSYNC_PROXY, env_keep+="no_proxy NO_PROXY"

User admin may run the following commands on RPI:
    (ALL : ALL) ALL
    (ALL) NOPASSWD: /bin/mount

- 编辑 -

roaima根据评论中的问题:

pi@RPI:~ $ ls -l /usr/bin/sudo
-rwsr-xr-x 1 root root 178432 Jan 14 04:29 /usr/bin/sudo

答案1

您的脚本有if ! grep -qs '/dev/sda1' /proc/mounts; then,我认为这是为了解决为每个实例运行此脚本的问题[email protected]。如果另一个实例正在运行(或过去运行过),则挂载将已经存在,因此此检查是必要的,否则您ExecStartPre=将失败。

我的另一个答案描述了如何sudo从脚本中删除,但另一个解决方案是用 systemd 的内置mount单元替换脚本。

该单元可以简单如下:

# /etc/systemd/system/media-pi-MyBook.mount
[Mount]
What=/dev/sda1
Where=/media/pi/MyBook

然后,不要将其放在您的覆盖中:

# /etc/systemd/system/[email protected]/override.conf
[Service]
ExecStartPre=/usr/local/bin/mount-sync-drive.sh

执行此操作可确保在运行服务之前挂载可用并正在运行。

# /etc/systemd/system/[email protected]/override.conf
[Unit]
Requires=media-pi-MyBook.mount
After=media-pi-MyBook.mount

现在您可以删除自定义脚本。

这可以解决几个问题,例如能够控制何时卸载单元,以及确保模板的每个实例都存在安装,而无需任何额外的检查。

要卸载,只需简单地操作,它就会自动停止sudo systemctl stop media-pi-MyBook.mount任何服务。Requires=这是编写脚本更加困难的事情,尤其是当您有大量模板实例时。

一个额外的细节:

我推荐的覆盖是 in[email protected]/而不是[email protected]/.这意味着模板的每个实例都将存在依赖性,syncthing@而不仅仅是syncthing@admin.

答案2

从状态检查开始:

systemctl show [email protected] | grep -E 'ProtectSystem|NoNewPrivileges'

您很可能已NoNewPrivileges启用。这样做的结果是你的进程不被允许成为 root,因此sudo无法运行。

如果是这种情况,您需要禁用该设置。请参阅我的回答rsyncd service ProtectSystem=off 无效,它相似但不重复,以获取如何更改这些值的完整说明

答案3

sudo不适用于脚本调用。其目的是验证交互式用户。

您应该尝试重新编写脚本以避免sudo.您的脚本仅适用sudo于一行,但其他行不会做太多事情,因此将root权限扩展到这一行也不是不合理的。

man systemd.service描述“特殊可执行前缀”。您可以使用这些前缀来ExecStartPre=更改行为。您对+以完全权限运行脚本特别感兴趣。

在您的插件中,只需将其添加+到脚本路径之前即可:

[Service]
ExecStartPre=+/usr/local/bin/mount-sync-drive.sh

然后您可以sudo从脚本中删除:

#!/bin/bash

exec &>> /var/log/syncthing.log
echo ""
date

# Check if /dev/sda1 is already mounted
if ! grep -qs '/dev/sda1' /proc/mounts; then
    # Mount /dev/sda1 to /media/pi/MyBook
    echo "Mounting /dev/sda1 to /media/pi/MyBook"
    mount -v /dev/sda1 /media/pi/MyBook
fi

额外加分:您在这里进行了大量登录。请注意,mount已经将它所做的事情打印到标准输出,因此您的 echo 命令有点多余。您还回显换行符和日期。默认情况下,您的设备会自动将脚本的所有标准输出和日期记录到日志中。因此,如果您选择使用日志,yopu 可以删除这些内容以简化脚本。

#!/bin/bash

if ! grep -qs '/dev/sda1' /proc/mounts; then
    mount -v /dev/sda1 /media/pi/MyBook
fi

然后您可以使用以下命令检查输出:

$ sudo journalctl -u syncthing*
Feb 21 17:23:14 RPI systemd[1]: Started [email protected] - Syncthing - Open Source Continuous File Synchronization for admin
Feb 21 17:23:14 RPI mount-sync-drive.sh[1234]: mount: /dev/sda1 mounted on /media/pi.

相关内容