我已将sudo配置为在没有密码的情况下运行,但是当我尝试运行ssh 'sudo Foo'时,仍然收到错误消息sudo: sorry, you must have a tty to run sudo

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

#1 楼

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

Defaults requiretty


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

Red Hat已经确认了该问题,并将在以后的发行版中将其删除。

如果更改服务器的配置这不是一个选择,作为针对该错误配置的解决方法,您可以对-t使用-ttssh选项,这会在远程端生成伪终端,但请注意,它具有许多副作用。 />
-tt供交互式使用。它将本地终端置于raw模式,以便您与远程终端进行交互。这意味着,如果ssh I / O不是从终端到终端,则会有副作用。例如,所有输入将被回显,特殊的终端字符(^?^C^U)将引起特殊处理;在输出时,LF s将转换为CRLF s ...(有关更多详细信息,请参见“为什么要更改此二进制文件?”的此答案。

要最大限度地减少影响,可以将其调用为:

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'


(假设(对于两者)远程用户的登录外壳都类似于Bourne)。

评论


非常感谢您:我今天使用了最后一个技巧(脚本-qec ....)。我在前后添加了一些命令:ssh host'cmds before; SHELL = / bin / sh脚本-qec“在此处使用args <&3>&4 2>&5 3 <&-4>&-5>&-” sudo cmdsudoed“ / dev / null 3 <&0 4>&1 5>&2;此处的cmds'#之后的cmd不会显示...可能是由于所有这些&-?他们是强制性的吗? (如果我正确理解了顺序:它们检索stdin,stdout和stderr的当前值(= fd),将sudo的in /​​ out / err重定向(复制)到相同的目的地,然后将其关闭以进行脚本处理?从而关闭外部也是stdin / out / err吗?)

–奥利维尔·杜拉克(Olivier Dulac)
20 Dec 3在13:23



此外,我记得在此站点上读过的文章不建议关闭fd0 1或2:[编辑:找到它:当然,它是从您那里来的:)):unix.stackexchange.com/a/446591/27616:我不知道在关闭3、4、5之后看不到命令​​的输出:这是否意味着它关闭了我的ssh shell的0、1和2?因此...我的后续命令可能最终在错误的地方书写? :/

–奥利维尔·杜拉克(Olivier Dulac)
20 Dec 3在13:35



@OlivierDulac,没有n>&-(或n <&-相同)关闭fd n。从现在开始,只有exec 0 <&-1 <&-2 <&-(或exec <&->&-2>&-)会关闭stdin / stdout / stderr。我们在脚本启动的shell中关闭sudo的fds 3、4、5,因为sudo和cmd都不需要它们,并且它们已经达到了目的(在脚本会话中还原原始的远程shell stdin / out / err)。我不知道为什么您在这里之后看不到cmds的输出。

–StéphaneChazelas
20 Dec 3'14:15



感谢您的回答,我也感到困惑,并且需要进一步测试以弄清为什么会这样...

–奥利维尔·杜拉克(Olivier Dulac)
20 Dec 7'在8:33

#2 楼

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

ssh -t someserver sudo somecommand


-t强制分配伪tty。

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

评论


不,这不是默认值。只是sudo的redhat发行版在其默认sudoers中具有requiretty。它将在新版本中修复

–StéphaneChazelas
2014年4月1日在20:28

@StephaneChazelas +1启发我说它很大程度上是Red Hat及其兄弟姐妹的本机,如果可以的话,请提供另一个++!

– JRFerguson
2014年4月1日在20:38

#3 楼

使用对-tssh标志来强制tty分配。

$ ssh luci tty
not a tty
$ ssh luci -t tty
/dev/ttys003
$


评论


当由于stdin不是终端而不会分配伪终端时,添加第二个-t强制分配。

– Samveen
17年1月1日在9:35

#4 楼

我在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

评论


这个答案对我来说也是最有意义的,同时使用Docker和CentOS 7。这很容易理解,并且易于复制/粘贴!

–大Shaun
16年5月2日在18:58



#5 楼

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

!requiretty

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

#6 楼

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

myscript=$(cat ssh_test.sh)
ssh -t user@host "$myscript"


说明:


放置要运行的命令(包括sudo命令)到脚本中,例如“ ssh_test.sh”。
将整个脚本读入一个名为“ myscript”的变量。
仅用-t调用ssh并提供该变量而不是命令。

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

#7 楼

我在Googling时发现了这个问题,并且由于完全不同的原因遇到了此错误。

我的解决方法是在已经调用了父Shell脚本的情况下,停止从父Shell脚本以sudo的形式调用下游Shell脚本。与sudo