【发布时间】:2017-10-31 13:29:10
【问题描述】:
我正在编写一个运行各种 shell 命令的 PHP 程序。有时它需要调用su,并且根据设计,我希望它提示输入提升的特权密码。在 PHP 中使用 passthru() 可以很好地解决这个问题。
我选择只为我的程序编写功能测试,因为它依赖于ssh、su 和其他 shell 命令。因此,我想在 PHPUnit 中运行真实的东西,看看它是否按预期工作。
由于这需要 SSH 服务器和用户帐户配置,我已将测试设置为在 Docker 中运行。这种方法看起来会很好 - 图像构建,当它运行时它调用 PHPUnit,然后退出。我希望有一种方法可以通过 Docker 将结果返回到调用系统,例如 Travis CI。
我已选择 Alpine Linux 作为我的基本 Docker 映像,但我遇到了终端分配问题。我最初认为 PHPUnit 会妨碍(请参阅此问题的原始版本),但我现在已将其范围缩小到 SSH,可以由 PHP 运行,甚至可以在控制台上运行。
这很好用:
su -c whoami
但是,这不是:
ssh localhost -t 'su -c whoami'
我明白了:
su:必须是 suid 才能正常工作
与 localhost 的连接已关闭。
请注意,ssh 设置了对 localhost 的无密码访问(用于测试目的),因此我希望输入的唯一密码是 su。
ssh 的手册建议 -f 有助于在哪里输入密码(开关“请求 ssh 在命令执行之前转到后台”)所以我试试这个:
ssh localhost -t -f 'su -c whoami'
我得到:
不会分配伪终端,因为 stdin 不是终端。
4275760bde94:~$ su: 必须 suid 才能正常工作
啊,又一个错误!好的,所以I've tried these ideas,特别是强制终端:
ssh localhost -tt -f 'su -c whoami'
double-t 仍然会发出关于 SUID 的抱怨,并且仍然不起作用。
但是,如果我在我的 Ubuntu 开发机器上执行此操作(也配置了对自身的 PPK 访问),它可以正常工作:
$ ssh localhost -t 'su -c whoami'
Password:
root
Connection to localhost closed.
这看起来像是 Alpine 或 BusyBox 的 OpenSSH 有问题。我该如何进一步深入研究?
一种解决方案就是换到另一个基础发行版,Ubuntu 肯定可以正常工作,但这会大大增加我的 Docker 映像大小(目前总计 68M 非常不错)。所以,如果可以的话,我想在 Alpine 坚持一段时间。
不太可能是 Docker
我确实想知道 Docker 是否会阻止创建或连接终端,但很快就打折了,因为我可以使用 docker exec -it container_name sh 获得交互式 shell。此外,我可以在 Docker shell 内的两个单独命令中执行 ssh 然后 su 就好了。
Bash 没有帮助
我注意到 Bash 在 Alpine 中可用,但这也没有帮助,这让我感到惊讶:
/ $ apk add bash
bash-4.3$ bash
bash-4.3$ su nonpriv
bash-4.3$ ssh localhost whoami
nonpriv
bash-4.3$ ssh localhost 'su -c whoami'
su: must be suid to work properly
bash-4.3$ ssh localhost 'su -s /bin/bash -c whoami'
su: must be suid to work properly
bash-4.3$ ssh -t localhost 'su -s /bin/bash -c whoami'
su: must be suid to work properly
Connection to localhost closed.
bash-4.3$ ssh -tt localhost 'su -s /bin/bash -c whoami'
su: must be suid to work properly
Connection to localhost closed.
bash-4.3$ ssh -tf localhost 'su -s /bin/bash -c whoami'
Pseudo-terminal will not be allocated because stdin is not a terminal.
bash-4.3$ su: must be suid to work properly
bash-4.3$ ssh -ttf localhost 'su -s /bin/bash -c whoami'
bash-4.3$ su: must be suid to work properly
Connection to localhost closed.
尝试shell插值
我发现这几乎可以工作:
/ $ ssh -t localhost "$( su -c whoami )"
sh: Password:: not found
sh: root: not found
Connection to localhost closed.
这使用标准的 Alpine sh shell,并使用 "$()" 构造,在上述链接中找到,我不完全理解。它输出Password:,即su中的提示符,然后等待密码。输入密码后,运行whoami,打印root。
所以看起来它正在运行命令,但我不确定它是否立即运行whoami,然后将其传递给ssh(不是我想要的),或者它是否正在获取远程shell localhost 然后做它(这就是我的意图)。
在任何情况下,它都试图运行 stdout 行,就好像它们本身就是命令一样。我怎样才能让它打印通过 SSH 运行的输出?
【问题讨论】:
-
我真的不知道,但很好奇完整性,你的测试是什么样的?
-
感谢@Jeff,事实证明这实际上并不是 PHPUnit 的问题。它确实会妨碍及时触发
expect的输出,但我可以通过超时来缓解这种情况。看起来问题在于 Alpine 如何允许将命令包含在ssh命令中。我想知道我在 SSH 中是否缺少某些标志。 -
当我有时间我会简化这个问题,因为 PHPUnit 的事情似乎是一个红鲱鱼。
-
乍一看这是duplicate of this question,但那里的解决方案不起作用。我想知道我是否正在研究 Alpine 特有的问题?
-
我已经重写了这个问题,专注于我认为问题的核心。
标签: shell docker terminal alpine