在一台机器上,我(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
也能正常工作。
此时,正确的引用并非易事。让我们分析一下该命令会发生什么。
- 首先,本地 shell 解析该字符串。它使用最外层的引号(如果有的话)来正确解析它。
ssh
将其参数作为数组获取。shell 用完的引号不会到达这里。ssh
决定哪些参数应该传递给远程端并构建一个字符串(类似于printf
我们的远程脚本)。- 然后,远程 shell(由
sshd
服务器上生成的 shell)会解析此字符串。远程 shell 使用(现在)最外层的引号(如果有)来正确解析它。 su-ser
将其参数作为数组获取。远程 shell 用完的引号不会传到这里。su-ser
建立一个字符串。su
然后,另一个 shell(由服务器上生成)解析此字符串。该 shell 使用(现在)最外层的引号(如果有)来正确解析它。- 您传递的命令将其参数作为数组获取。上一个 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的装置可以工作,但是这太复杂了,我甚至不会尝试。
因此,该脚本可能对您来说足够,也可能不够;这取决于您需要运行的命令。现在您知道了它的几个局限性。祝您好运。