it-swarm.cn

如果我可以在没有密码的情况下进行Sudo,为什么需要tty来运行Sudo?

我已将Sudo配置为无需密码即可运行,但是当我尝试ssh 'Sudo Foo',我仍然收到错误消息Sudo: sorry, you must have a tty to run Sudo

为什么会发生这种情况,我该如何解决?

229
merlin2011

那可能是因为您的/etc/sudoers文件(或其包含的任何文件)具有:

Defaults requiretty

...使得Sudo需要TTY。已知Red Hat系统(RHEL,Fedora ...)在默认sudoers文件中需要TTY。这并没有提供真正的安全优势,可以安全删除。

Red Hat已经确认该问题 ,它将在以后的版本中删除。

如果不能更改服务器的配置,则可以使用-t-tt选项设置为ssh,以在远程端生成伪终端,但是请注意,不要更改服务器的配置。它有许多副作用。

-tt用于交互使用。它将本地终端置于raw模式,以便您与远程终端进行交互。这意味着,如果ssh I/O不是从终端到终端,则会有副作用。例如,所有输入将被回显,特殊的终端字符(^?^C^U)将引起特殊处理;在输出时,LFs将转换为CRLFs ...(请参阅 此答案为什么要更改此二进制文件? 了解更多详情。

为了最大程度地减少影响,可以按以下方式调用它:

ssh -tt Host 'stty raw -echo; Sudo ...' < <(cat)

< <(cat)将避免在raw模式下设置本地终端(如果有)。我们正在使用stty raw -echo设置远程终端的线路规则为直通(有效,因此它的行为就像不使用-tt的伪终端一样,将被使用的管道,尽管仅在该命令运行后才适用,所以您需要延迟发送一些输入内容,直到发生这种情况)。

请注意,由于远程命令的输出将到达终端,这仍然会影响其缓冲(对于许多应用程序,它是基于行的)和带宽效率,因为TCP_NODELAY处于打开状态。同样使用-ttssh会将IPQoS设置为lowdelay,而不是throughput。您可以使用以下两种方法来解决:

ssh -o IPQoS=throughput -tt Host 'stty raw -echo; Sudo cmd | cat' < <(cat)

另外,请注意,这意味着远程命令无法在其stdin上检测到文件结尾,并且远程命令的stdout和stderr合并为单个流。

因此,毕竟不是很好的解决方法。

如果您有办法在远程主机上生成伪终端(例如expectzshsocatPerlIO::Pty...),那么最好使用它来创建伪终端以将Sudo附加到(但不用于I/O),并使用ssh而不使用-t

例如,使用expect

ssh Host 'expect -c "spawn -noecho sh -c {
     exec Sudo cmd >&4 2>&5 <&6 4>&- 5>&- 6<&-}
 exit [lindex [wait] 3]" 4>&1 5>&2 6<&0'

或使用script(此处假定从util-linux实现):

ssh Host 'Shell=/bin/sh script -qec "
              Sudo cmd <&3 >&4 2>&5 3<&- 4>&- 5>&-
            " /dev/null 3<&0 4>&1 5>&2'

(假设(对于这两者而言)远程用户的登录Shell类似于Bourne)。

294
Stéphane Chazelas

默认情况下,Sudo配置为需要TTY。也就是说,应该从登录Shell运行Sudo。您可以通过在SSH调用中添加-t开关来满足此要求:

ssh -t someserver Sudo somecommand

-t强制分配伪tty。

如果要全局执行此操作,请修改/etc/sudoers以指定!requiretty。可以按每个用户,每个组或所有级别进行。

30
JRFerguson

使用 -t标记为ssh以强制tty分配。

$ ssh luci tty
not a tty
$ ssh luci -t tty
/dev/ttys003
$
18
Kyle Jones

我在使用Docker和Centos 7时遇到了这个问题。我最终做了以下工作:

yum install -y Sudo

sed -i -e 's/Defaults requiretty.*/ #Defaults requiretty/g' /etc/sudoers

我在 https://hub.docker.com/r/liubin/fluentd-agent/~/dockerfile 中发现了此黑客

11
Martin Tapp

一个有趣的替代方法是运行FreeIPA或IdM来集中管理用户和更严格的规则。然后,您可以创建Sudo规则并分配选项

!requiretty

在规则中。然后该命令将按预期运行。您还可以从一组配置中管理所有服务器和用户。

1
strtluge

我遇到过同样的问题。就我而言,解决方案是两行

myscript=$(cat ssh_test.sh)
ssh -t [email protected] "$myscript"

说明:

  • 将要运行的命令(包括Sudo命令)放入脚本中,例如“ ssh_test.sh”。

  • 将整个脚本读取到一个名为“ myscript”的变量中。

  • 仅用-t调用ssh并提供变量而不是命令。

在此之前,我遇到了从标准输入读取和使用heredocs组合使用的问题

0
Gerry Hickman