如何修复 Alpine Linux 中的 "Pseudo-terminal will not be allocated because stdin is not a terminal"?

How to fix "Pseudo-terminal will not be allocated because stdin is not a terminal" in Alpine Linux?

我正在编写一个 PHP 程序,其中包含 运行 各种 shell 命令。有时它需要调用 su,根据设计,我希望它提示输入提升权限的密码。在 PHP 中使用 passthru() 对此效果很好。

我选择只为我的程序编写功能测试,因为它依赖于 sshsu 和其他 shell 命令。因此,我想 运行 PHP 单元中的真实内容,看看它是否按我预期的那样工作。

由于这需要 SSH 服务器和用户帐户配置,因此我在 Docker 中将测试设置为 运行。这种方法看起来会很好 - 图像构建,当它 运行s 它调用 PHPUnit,然后退出。我希望有一种方法可以通过 Docker 将结果 return 发送到调用系统,例如 Travis CI.

我选择了 Alpine Linux 作为我的基础 Docker 图像,但是我在终端分配方面遇到了问题。我最初认为 PHPUnit 妨碍了(请参阅此问题的原始版本)但我现在将其范围缩小到 SSH,运行 by PHP 或者甚至只是在控制台。

这很好用:

su -c whoami

然而,这不是:

ssh localhost -t 'su -c whoami'

我得到:

su: must be suid to work properly
Connection to localhost closed.

请注意,ssh 设置为无密码访问本地主机(用于测试目的),因此我希望输入的唯一密码是 su

ssh 的手册建议 -f 有助于要求输入密码的地方(开关 "requests ssh to go to background just before command execution")所以我试试这个:

ssh localhost -t -f 'su -c whoami'

然后我得到:

Pseudo-terminal will not be allocated because stdin is not a terminal.
4275760bde94:~$ su: must be suid to work properly

啊,又是一个错误!好的,所以 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,并使用 "$()" 构造,在上述 link 上找到,我不完全理解。输出Password:,也就是su中的提示,然后等待输入密码。输入密码后 whoami 为 运行,打印出 root.

所以它看起来像是 运行ning 命令,但我不确定它是否立即 运行ning whoami 然后传递给 ssh(不是我想要的)或者它是否正在获取远程 shell 到本地主机然后再执行它(这就是我想要的)。

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

我在我的问题中猜测这将在 Ubuntu 容器中工作,事实证明这是正确的。有趣的是,我仍然收到此命令的 "must be run from a terminal" 错误:

su -c whoami

但这里不是,终端在 SSH 无密码命令中明确分配给自己:

ssh -t localhost 'su -c whoami'

不幸的是,新的 OS 将我的 68M 图片增加到了 430M,呃!因此,我应该很高兴收到使它在 Alpine 上运行的新答案。