使用非 root 脚本部分以 root 身份运行 Bash 脚本

使用非 root 脚本部分以 root 身份运行 Bash 脚本

我有一个 bash 脚本需要以 root 身份运行才能完成一项任务,在这种情况下,它是让验证器拍摄 Helium 区块链的快照。

我已编辑 /etc/sudoers 文件,以允许我以 root 身份运行此脚本。这工作正常。

useraccount   ALL=(ALL:ALL) NOPASSWD:/home/useraccount/validator_data/snapshotmaker.sh

脚本中的命令如下:

sudo docker exec validator miner snapshot take /var/data/$dtt

此后,该命令会生成如下文件'30-10-2021T233752.bin“”。

我的下一步是获取此文件并将其复制到 IPFS,以便我可以共享它。执行此操作的命令是:

ipfs files cp /ipfs/$(ipfs add -Q $localfile) $ip

目前我收到以下错误:

Error: no IPFS repo found in /root/.ipfs. please run: 'ipfs init'

这是因为当配置在我的用户帐户中时,它试图以 root 身份运行它。

我曾尝试在脚本执行过程中切换帐户,但似乎会失败。

所以我的问题是如何以我的原始用户身份从根脚本中运行 IPFS 命令。

我的 Bash 脚本:

#!/bin/bash

dt=$(date '+%d-%m-%YT%H%M%S');
dtt="${dt}.bin"
a='/var/data/'
c="${a}${dt}.bin"

echo "${c}"

sudo docker exec validator miner snapshot take /var/data/$dtt


localfile="/home/useraccount/validator_data/${dt}.bin"
echo "LocalFile: ${localfile}"

ip=" /Helium/Snapshots/2021/${dt}.bin"
echo "IPFS Location: ${ip}"

sleep 2

if [ -f "$localfile" ]; then
        echo "$localfile exists."
        sudo chown useraccount $localfile
        whoami
        su - useraccount
        whoami
        ipfs files cp /ipfs/$(ipfs add -Q $localfile) $ip
        #ipfs files cp /ipfs/$(ipfs add -Q <local-file>) "/Helium/Snapshots/2021/<dest-name>"
else 
    echo "$localfile does not exist."
fi

输出如下:

/var/data/31-10-2021T005728.bin
ok
LocalFile: /home/useraccount/validator_data/31-10-2021T005728.bin
IPFS Location:  /Helium/Snapshots/2021/31-10-2021T005728.bin
/home/useraccount/validator_data/31-10-2021T005728.bin exists.
root

然后它就死机了。如果我删除该su行,就会出现本文开头提到的根本问题。

希望有人可以帮忙。

答案1

我做了一个“试运行”测试,没有docker和你在里面做什么,也没有ipfs。方法应该经过一些调整后即可使用真实程序为您工作。

  • scrip以普通用户身份运行 shellscript ,而不是使用sudo

  • 编辑脚本,将我的演示中的“测试人员”更改为您的用户名。

  • sudo使用以下方式编辑无需密码的精确命令行visudo

    $ LANG =C sudo tail -n2 /etc/sudoers
    %tester ALL=NOPASSWD: /usr/sbin/docker exec validator miner snapshot take /var/data/tmpfil
    %tester ALL=NOPASSWD: /usr/bin/chown tester /home/tester/validator_data/tmpfil
    
    • 对于 sudo 操作来说,拥有一个固定的文件名称非常重要。之后可以根据时间赋予一个名称。
    • 检查docker可执行文件的位置(可能不在/usr/sbin)。

我修改后的脚本scrip

#!/bin/bash

if [ "$(whoami)" != "tester" ]
then
 echo "run as 'tester'"
 exit
fi

dt=$(date '+%d-%m-%YT%H%M%S');
dtt="${dt}.bin"
a='/var/data/'
c="${a}${dt}.bin"

echo "${c}"

sudo /usr/sbin/docker exec validator miner snapshot take /var/data/tmpfil

if [ -f "/home/tester/validator_data/tmpfil" ]; then
        ls -l "/home/tester/validator_data/tmpfil"

        sudo /usr/bin/chown tester "/home/tester/validator_data/tmpfil"
        mv "/home/tester/validator_data/tmpfil" "/home/tester/validator_data/${dt}.bin"
        localfile="/home/tester/validator_data/${dt}.bin"
        echo "LocalFile: ${localfile}"
        ls -l "${localfile}"

        ip=" /Helium/Snapshots/2021/${dt}.bin"
        echo "IPFS Location: ${ip}"

        sleep 2

        echo "$localfile exists."
        whoami
        /usr/local/bin/ipfs files cp /ipfs/$(/usr/local/bin/ipfs add -Q $localfile) $ip
        #ipfs files cp /ipfs/$(ipfs add -Q <local-file>) "/Helium/Snapshots/2021/<dest-name>"
else 
    echo "$localfile does not exist."
fi

假装是命令行的脚本docker

#!/bin/bash

if [ "$EUID" == "0" ]
then
 echo "docker's world" > "/home/tester/validator_data/tmpfil"
 chown root:root "/home/tester/validator_data/tmpfil"
 echo "ok"
else
 echo "run with sudo"
fi

演示运行:

tester@lenovo-v130:~$ LANG=C ./scrip 
/var/data/01-11-2021T051748.bin
ok
-rw-r--r-- 1 root root 15 Nov  1 05:17 /home/tester/validator_data/tmpfil
LocalFile: /home/tester/validator_data/01-11-2021T051748.bin
-rw-r--r-- 1 tester root 15 Nov  1 05:17 /home/tester/validator_data/01-11-2021T051748.bin
IPFS Location:  /Helium/Snapshots/2021/01-11-2021T051748.bin
/home/tester/validator_data/01-11-2021T051748.bin exists.
tester
./scrip: line 34: ipfs: command not found
./scrip: line 34: ipfs: command not found

答案2

所以我的问题是如何以我的原始用户身份从根脚本中运行 IPFS 命令。

sudo su - useraccount -c COMMAND

答案3

首先,您需要为您的脚本创建一个 sudo 配置,在此示例中,我们将其放置在/etc/sudoers.d具有权限的环境中440

Cmnd_Alias CMDS = /opt/bin/docker_example.sh
User_Alias CMDUSERS = bac0n
CMDUSERS ALL=(ALL) NOPASSWD: CMDS
Defaults!CMDS !requiretty

我们将脚本命名为docker_example.sh,如 sudo 示例所示:

#!/bin/bash

# Exit immediately on non-zero exit status.
set -e

((EUID != 0)) && {
    echo This script should run as root.
    exit 1
}

[[ ${SUDO_USER+ } ]] && \
user_account=$SUDO_USER || user_account=$(id -nu)

printf -v bin_file \
'%(%d-%m-%YT%H%M%S)T.%s' -1 bin

local_file=$HOME/validator_data/$bin_file
 ipfs_file=/Helium/Snapshots/2021/$bin_file

printf '
Bin File: %s
Local File: %s
IPFS File: %s
' "$bin_file" "$local_file" "$ipfs_file"

docker exec validator miner snapshot take "/var/data/$bin_file"
sleep 2

[[ -f $local_file ]] || {
    echo File does not exist: "$local_file"
    exit 1
}

chown $user_account "$local_file"

#
# su $user_account -c 'echo whoami: $1, su: $(id -nu)' _ $(id -nu)
#
su $user_account -c 'ipfs files cp "/ipfs/$(ipfs add -Q "$1")" "$2"' _ "$local_file" "$ipfs_file"

现在您应该能够使用 sudo 将此脚本添加到 crontab,并且它应该使用 NOPASSWD 运行。

$ sudo crontab -u bac0n -e
# min hour dom month dow command
* * * * * sudo /opt/bin/docker_example.sh > /dev/null 2>&1

相关内容