管道ssh sudo

时间:2019-05-09 10:58:12

标签: ssh sudo tty

有时我需要以root用户身份在远程服务器上运行命令,并在本地服务器上解析命令的输出。远程服务器不允许通过ssh进行root登录,但是以要求输入密码的方式配置了sudo。我需要做的一个简化示例是

ssh remote sudo echo bar | tr bar foo

(显然,在此简化示例中,没有充分的理由需要在echo之外的另一台机器上运行tr:这只是一个玩具示例,用于说明我要执行的操作。 )

如果我运行上面的命令,则会收到一个错误,提示sudo无法提示输入密码:

richard@local:~$ ssh remote sudo echo bar | tr bar foo
sudo: no tty present and no askpass program specified

我可以尝试解决此问题的一种方法是在-t中添加ssh选项。如果这样做,sudo确实会等待并接受密码,但是ssh的伪终端的输出将进入stdout,这意味着sudo提示消息将通过管道传递到tr并不显示给用户。如果用户不知道sudo正在等待密码,他们会认为脚本已挂起,并且将提示消息传递给管道可能会中断进一步的处理:

richard@local:~$ ssh -t remote sudo echo bar | tr bar foo
[sudo] posswood foo oichood: 
foo

(这个愚蠢的示例显示提示已由输出通过管道传输到的tr命令处理。)

我可以尝试解决此问题的另一种方法是在-S中添加sudo选项。如果这样做,sudo会在stderr上提示输入密码,因此提示不会沿着管道传递。很好,但是sudo也接受标准输入上的密码,这意味着它会回显到终端上,任何人在用户肩膀上看都可以读取它:

richard@local:~$ ssh remote sudo -S echo bar | tr bar foo
[sudo] password for richard: p8ssw0rd
foo

我找到了解决这两个问题的巧妙方法,但是如果用户第一次输入密码错误,我的解决方法就会遇到问题。这本身就是一个问题。例如:

richard@local:~$ echo "[sudo] password for $USER:"; \
  ssh -t remote sudo echo bar | tail +2 | tr bar foo

richard@local:~$ (read -s password; echo $password; echo >&2) \
  | ssh remote sudo -S echo bar | tr bar foo

我敢肯定,对此必须有一个好的解决方案,因为这似乎并不罕见。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

我想出的最好的解决方案是使用sudo -S并禁用本地回显,这样在键入密码时不会显示密码:

$ { stty -echo; ssh remote sudo -S echo hello; stty echo; echo 1>&2; }
[sudo] password for user:
hello

这使sudo负责密码提示,因此如果用户输入错误密码,它便可以正常工作。

我认为使用ssh -t的任何解决方案都无法正常工作,因为它结合了stderr和stdout。