如何在 ssh 上使用 sudo 运行任意复杂的命令?

VoY*_*VoY 83 scripting ssh bash sudo

我有一个只能以我的用户名 (myuser) 登录的系统,但我需要以其他用户 (scriptuser) 身份运行命令。到目前为止,我想出了以下来运行我需要的命令:

ssh -tq myuser@hostname "sudo -u scriptuser bash -c \"ls -al\""
Run Code Online (Sandbox Code Playgroud)

但是,如果当我尝试运行更复杂的命令时,例如[[ -d "/tmp/Some directory" ]] && rm -rf "/tmp/Some directory"我很快就会遇到引用问题。我不确定如何将这个示例复杂命令传递给bash -c,当\"已经分隔了我传递的命令的边界时(所以我不知道如何引用 /tmp/Some 目录,其中包含一个空格。

无论引用多么复杂/疯狂,是否有通用解决方案允许我传递任何命令,或者这是我达到的某种限制?是否有其他可能的,也许更具可读性的解决方案?

Tho*_*mBR 152

我有时使用的一个技巧是使用 base64 对命令进行编码,并将其通过管道传输到另一个站点上的 bash:

MYCOMMAND=$(base64 -w0 script.sh)
ssh user@remotehost "echo $MYCOMMAND | base64 -d | sudo bash"
Run Code Online (Sandbox Code Playgroud)

这将对脚本进行编码,在安全字符串中包含任何逗号、反斜杠、引号和变量,并将其发送到其他服务器。(-w0需要禁用换行,默认情况下发生在第 76 列)。另一方面,$(base64 -d)将解码脚本并将其提供给要执行的 bash。

无论脚本多么复杂,我都没有遇到任何问题。解决了转义问题,因为你不需要转义任何东西。它不会在远程主机上创建文件,您可以轻松运行极其复杂的脚本。

  • 这里也有一个无用的 echo 用法。`base64 脚本 | ssh 远程主机 'base64 -d | sudo bash'` 就足够了:) (9认同)
  • 甚至:`ssh user@remotehost "echo \`base64 -w0 script.sh\` | base64 -d | sudo bash"` (2认同)

moe*_*eye 35

看到-tt选项了吗?阅读ssh(1)手册。

ssh -tt root@host << EOF
sudo some # sudo shouldn't ask for a password, otherwise, this fails. 
lines
of
code 
but be careful with \$variables
and \$(other) \`stuff\`
exit # <- Important. 
EOF
Run Code Online (Sandbox Code Playgroud)

我经常做的一件事是使用 vim 并使用:!cat % | ssh -tt somemachine技巧。

  • 当然`:!cat % | (command)` 可以作为 `:w !(command)` 或 `:!(command) &lt; %` 完成。 (3认同)
  • 是的。我的台词是[猫虐待](http://en.wikipedia.org/wiki/Cat_%28Unix%29#Useless_use_of_cat) (2认同)

小智 10

我认为最简单的解决方案在于修改@thanasisk 的评论。

创建一个脚本,scp把它放到机器上,然后运行它。

rm在开始时有脚本本身。shell 已经打开了该文件,因此它已被加载,然后可以毫无问题地将其删除。

通过按照这个顺序做事(rm首先,其他东西第二)它甚至会在它在某个时候失败时被删除。


Tom*_*ech 8

您可以使用%q格式说明符 withprintf来处理变量转义:

cmd="ls -al"
printf -v cmd_str '%q' "$cmd"
ssh user@host "bash -c $cmd_str"
Run Code Online (Sandbox Code Playgroud)

printf -v将输出写入变量(在本例中为$cmd_str)。我认为这是最简单的方法。无需传输任何文件或对命令字符串进行编码(只要我喜欢这个技巧)。

这是一个更复杂的示例,表明它也适用于方括号和与号之类的内容:

$ ssh user@host "ls -l test"
-rw-r--r-- 1 tom users 0 Sep  4 21:18 test
$ cmd="[[ -f test ]] && echo 'this really works'"
$ printf -v cmd_str '%q' "$cmd"
$ ssh user@host "bash -c $cmd_str"
this really works
Run Code Online (Sandbox Code Playgroud)

我还没有测试过,sudo但它应该很简单:

ssh user@host "sudo -u scriptuser bash -c $cmd_str"
Run Code Online (Sandbox Code Playgroud)

如果需要,您可以跳过一个步骤并避免创建中间变量:

$ ssh user@host "bash -c $(printf '%q' "$cmd")"
this really works
Run Code Online (Sandbox Code Playgroud)

或者甚至完全避免创建变量:

ssh user@host "bash -c $(printf '%q' "[[ -f test ]] && echo 'this works as well'")"
Run Code Online (Sandbox Code Playgroud)


Dej*_*ton 8

更新:示例现在明确使用sudo.

这是一种将 Bash 语法与复合赋值结合使用,通过 sudo 通过 SSH 执行任意复杂命令的方法:

CMD=$( cat <<'EOT'
echo "Variables like '${HOSTNAME}' and commands like $( whoami )"
echo "will be interpolated on the server, thanks to the single quotes"
echo "around 'EOT' above."
EOT
) \
SSHCMD=$(
  printf 'ssh -tq myuser@hostname sudo -u scriptuser bash -c %q' "${CMD}" ) \
bash -c '${SSHCMD}'

CMD=$( cat <<EOT
echo "If you want '${HOSTNAME}' and $( whoami ) to be interpolated"
echo "on the client instead, omit the the single quotes around EOT."
EOT
) \
SSHCMD=$(
  printf 'ssh -tq myuser@hostname sudo -u scriptuser bash -c %q' "${CMD}" ) \
bash -c '${SSHCMD}'
Run Code Online (Sandbox Code Playgroud)

正确格式化命令以在其他地方动态执行(例如嵌套 shell、远程 SSH shell 等)可能非常棘手 -有关原因的详细说明,请参见/sf/answers/3723834691/。复杂的 bash 结构,如上面的语法,可以帮助这些命令正常工作。

有关如何cat<<组合形成内联此处文档的更多信息,请参阅/sf/answers/1523336951/


小智 5

您是否知道可以使用sudo它为您提供一个 shell,您可以在其中以所选用户的身份运行命令?

-i, --登录

运行由目标用户的密码数据库条目指定的 shell 作为登录 shell。这意味着 shell 将读取特定于登录名的资源文件,例如 .profile 或 .login。如果指定了命令,则会通过 shell 的 -c 选项将其传递给 shell 以执行。如果未指定命令,则执行交互式 shell。sudo 在运行 shell 之前尝试更改到该用户的主目录。通讯?mand 的运行环境类似于用户在登录时会收到的环境。sudoers(5) 手册文档中的命令环境部分?说明了 -i 选项如何影响在使用 sudoers 策略时运行命令的环境。