如何解决Alpine Linux中"由于stdin不是终端而无法分配伪终端"的问题?

hal*_*fer 5 shell terminal docker alpine-linux

我正在编写一个运行各种shell命令的PHP程序.有时它需要调用su,并且按照设计,我希望它提示提升特权密码.passthru()在PHP中使用可以正常工作.

我选择了编写功能测试只针对我的程序,因为它依赖于ssh,su和其他shell命令.因此,我想在PHPUnit中运行真实的东西,看看它是否像我期望的那样工作.

由于这需要SSH服务器和用户帐户配置,我已将测试设置为在Docker中运行.这种方法看起来很好 - 图像构建,运行时调用PHPUnit,然后退出.我希望有一种方法可以通过Docker将结果返回给调用系统,例如Travis CI.

我已选择Alpine Linux作为我的基本Docker镜像,但我遇到终端分配问题.我原本以为PHPUnit正在阻碍(参见这个问题的原始版本)但我现在已经缩小到SSH,无论是由PHP运行,还是仅在控制台运行.

这很好用:

su -c whoami
Run Code Online (Sandbox Code Playgroud)

但是,这不是:

ssh localhost -t 'su -c whoami'
Run Code Online (Sandbox Code Playgroud)

我明白了:

su:必须suid才能正常工作
连接到localhost关闭.

请注意,ssh设置了对localhost的无密码访问(用于测试目的),因此我希望输入的唯一密码就是那个su.

ssh建议的手册-f有助于要求密码的位置(交换机"在命令执行之前请求ssh转到后台")所以我试试这个:

ssh localhost -t -f 'su -c whoami'
Run Code Online (Sandbox Code Playgroud)

我得到:

由于stdin不是终端,因此不会分配伪终端.
4275760bde94:〜$ su:必须是suid才能正常工作

啊,另一个错误!好的,所以我尝试了这些想法,特别是强迫终端:

ssh localhost -tt -f 'su -c whoami'
Run Code Online (Sandbox Code Playgroud)

双t仍然会出现关于SUID的投诉,但仍然无效.

但是,如果我在我的Ubuntu开发机上执行此操作(也配置了PPK访问自己),它可以正常工作:

$ ssh localhost -t 'su -c whoami'
Password: 
root
Connection to localhost closed.
Run Code Online (Sandbox Code Playgroud)

这使它看起来像Alpine或BusyBox的OpenSSH有问题.我该如何进一步深入研究?

一个解决方案只是交换到另一个基础发行版,Ubuntu肯定会工作正常,但这将大大增加我的Docker图像大小(目前总共68M非常好).所以,如果可以的话,我想坚持使用Alpine.

不太可能是Docker

我确实想知道Docker是否可能阻止创建或附加终端,但很快就打了折扣,因为我可以使用它来获得交互式shell docker exec -it container_name sh.此外,我可以在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.
Run Code Online (Sandbox Code Playgroud)

尝试shell插值

我发现这几乎有用:

/ $ ssh -t localhost "$( su -c whoami )"
sh: Password:: not found
sh: root: not found
Connection to localhost closed.
Run Code Online (Sandbox Code Playgroud)

这使用标准的Alpine shshell,并使用"$()"上述链接中的构造,我并不完全理解.它输出Password:,这是提示输入su,然后等待密码.当输入密码时,whoami运行,打印root.

所以看起来它正在运行命令,但是我不确定它是否whoami立即运行然后将其传递给ssh(不是我想要的)或者它是否正在获取一个远程shell到localhost然后这样做(这是什么我打算).

在任何情况下,它都试图运行标准输出行,就好像它们本身就是命令一样.如何才能通过SSH打印输出?