从 sudo su 运行命令

从 sudo su 运行命令

在一台机器上,我(tlous)被授予以另一个用户身份打开 shell 的权限(serviceAccount

执行:sudo su - serviceAccount已达到以此用户身份打开 shell 的预期效果serviceAccount。到目前为止一切顺利。

这很好,但我想以该用户的身份运行命令而不打开 shell。

假设命令是whoami

我试过了:

sudo -u serviceAccount whoami

抱歉,用户 tlous 无权以 serviceAccount 身份执行“/usr/bin/whoami”...

sudo su - serviceAccount -c whoami

抱歉,用户 tlous 无权执行‘/bin/su - serviceAccount -c whoami’...

还有其他变体。我遗漏了什么?这可以在一行中完成吗?原因是我实际上想将其作为 ssh 命令运行: ssh -t [email protected] sudo su - serviceAccount -c whoami

答案1

sudoers远程端的文件可能指定了您可以运行的确切命令,并且它是su - serviceAccount。一个或多个附加选项(如-c)将使命令不合格。任何解决方案都应使用确切的su - serviceAccount命令。

有一种方法可以解决这个问题,但并不完美。首先在服务器上运行以下命令:

echo whoami | sudo su - serviceAccount

(尽管进行了重定向,sudo-S仍会使用终端询问您的密码(如果需要))。

为了使该方法更加通用,请在服务器上创建一个脚本:

#!/bin/sh
printf '%s ' "$@" | sudo su - serviceAccount

将其另存为su-ser,并使其可执行。现在你可以测试这些:

./su-ser whoami
./su-ser 'whoami; whoami'
./su-ser ls -l
./su-ser 'ls -l'

请注意,这些引号不会传播到由 生成的 shell su。每次printf从脚本获取的参数构建命令时,这都会作为细绳进而解析由最终的 shell 处理,包括单词拆分、通配符等。这意味着所有这些

./su-ser echo 1 2 3
./su-ser echo "1 2             3"
./su-ser "echo 1 2             3"

将打印1 2 3。要传递需要引用引号的字符串,例如:

./su-ser 'echo "1 2             3"'

下一步是从本地计算机触发此远程脚本:

ssh -t [email protected] '"/path/to/su-ser" whoami'

您需要-t以防万一sudo要求输入密码。从ssh您问题正文中的命令我可以看出您可能了解这一点。

注意ssh还构建了一个命令细绳。即使包含空格,上述引用也能正常工作/path/to/su-ser。另一方面,如果路径中没有空格(并且没有 , 等字符;*,则完全不加引号ssh … /path/to/su-ser whoami也能正常工作。

此时,正确的引用并非易事。让我们分析一下该命令会发生什么。

  1. 首先,本地 shell 解析该字符串。它使用最外层的引号(如果有的话)来正确解析它。
  2. ssh将其参数作为数组获取。shell 用完的引号不会到达这里。
  3. ssh决定哪些参数应该传递给远程端并构建一个字符串(类似于printf我们的远程脚本)。
  4. 然后,远程 shell(由sshd服务器上生成的 shell)会解析此字符串。远程 shell 使用(现在)最外层的引号(如果有)来正确解析它。
  5. su-ser将其参数作为数组获取。远程 shell 用完的引号不会传到这里。
  6. su-ser建立一个字符串。
  7. su然后,另一个 shell(由服务器上生成)解析此字符串。该 shell 使用(现在)最外层的引号(如果有)来正确解析它。
  8. 您传递的命令将其参数作为数组获取。上一个 shell 用完的引号不会传递到此处。

这意味着有时你需要引用级别以获得正确的结果。一个简单的本地命令,如

echo "1 2             3"

变成

ssh -t [email protected] "'/path/to/su-ser' 'echo \"1 2             3\"'"

其中未转义的双引号被本地 shell 剥离,单引号被远程 shell 剥离;最后,转义的双引号(实际上,只要本地 shell 剥离未转义的双引号,它们就会变成未转义的)告诉由 生成的 shell,su带有多个空格的字符串是 的单个参数echo。这样输出就是

1 2             3

另一个问题是远程脚本将命令传递给最终 shell 的标准输入,因此您无法轻松地将其标准输入用于其他目的。例如(尝试一下)应该打印回您输入的任何行(以+cat; whoami结尾),然后打印输出。但是,如果您在服务器上运行此命令:CtrlDwhoami

./su-ser 'cat; whoami'

cat将立即终止。这应该有效:

./su-ser 'cat /dev/tty; whoami'

(再次使用Ctrl+D终止cat)。现在比较一下此行为:

./su-ser '
whoami
whoami
whoami
'

更改为:

./su-ser '
whoami
cat
whoami
'

相同的流cat为 shell 提供信息;这不是一件好事。为实际命令和真正的 stdin 建立单独的通道可能并不容易,因为sudo默认情况下会关闭额外的文件描述符并设置一个新的最小环境。我猜测使用临时文件/fifos的装置可以工作,但是这太复杂了,我甚至不会尝试。

因此,该脚本可能对您来说足够,也可能不够;这取决于您需要运行的命令。现在您知道了它的几个局限性。祝您好运。

相关内容