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

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

我已配置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。这没有提供真正的安全优势,可以安全地删除。

红帽已经承认这个问题并且它将在未来的版本中删除。

如果无法更改服务器的配置,作为该错误配置的解决方法,您可以使用-t-tt选项ssh在远程端生成一个伪终端,但要注意它有多个端影响。

-tt用于交互式使用。它将本地终端置于raw模式下,以便您与远程终端交互。这意味着如果sshI/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 会合并到单个流中。

所以,这毕竟不是一个很好的解决方法。

如果您有办法在远程主机上生成伪终端(例如使用expect, zsh, socat,perlIO::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 类似)。

答案2

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

ssh -t someserver sudo somecommand

强制-t分配伪终端。

如果要全局执行此操作,请修改/etc/sudoers以指定!requiretty。这可以针对每个用户、每个组或所有级别来完成。

答案3

使用-t标志 tossh强制分配 tty。

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

答案4

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

!要求

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

相关内容