Eu configurei sudo
para executar sem uma senha, mas quando tento ssh 'sudo Foo'
, ainda recebo a mensagem de erro sudo: sorry, you must have a tty to run sudo
.
Por que isso acontece e como posso solucionar isso?
Eu configurei sudo
para executar sem uma senha, mas quando tento ssh 'sudo Foo'
, ainda recebo a mensagem de erro sudo: sorry, you must have a tty to run sudo
.
Por que isso acontece e como posso solucionar isso?
Respostas:
Provavelmente porque seu /etc/sudoers
arquivo (ou qualquer outro arquivo incluído) possui:
Defaults requiretty
... o que sudo
exige um TTY. Sabe-se que os sistemas Red Hat (RHEL, Fedora ...) exigem um TTY no sudoers
arquivo padrão . Isso não oferece nenhum benefício real de segurança e pode ser removido com segurança.
A Red Hat reconheceu o problema e ele será removido em versões futuras.
Se alterar a configuração do servidor não for uma opção, como uma solução alternativa para essa configuração incorreta, você poderá usar as opções -t
ou -tt
nas ssh
quais gera um pseudo-terminal no lado remoto, mas cuidado com o fato de ter vários efeitos
-tt
destina-se ao uso interativo. Ele coloca o terminal local no raw
modo para que você interaja com o terminal remoto. Isso significa que, se a ssh
E / S não for de / para um terminal, isso terá efeitos colaterais. Por exemplo, todas as entradas serão eco de volta, caracteres especiais terminais ( ^?
, ^C
, ^U
) irá causar um processamento especial; na saída, LF
s serão convertidos em CRLF
s ... (consulte esta resposta em Por que este arquivo binário está sendo alterado? para obter mais detalhes.
Para minimizar o impacto, você pode invocá-lo como:
ssh -tt host 'stty raw -echo; sudo ...' < <(cat)
O < <(cat)
evitará a configuração do terminal local (se houver) no raw
modo. E estamos usando stty raw -echo
para definir a disciplina de linha do terminal remoto como passagem (efetivamente, ele se comporta como o tubo que seria usado em vez de um pseudo-terminal sem -tt
, embora isso só se aplique após a execução desse comando, então você precisa atrasar o envio de algo para entrada até que isso aconteça).
Observe que, como a saída do comando remoto será direcionada para um terminal, isso ainda afetará seu buffer (que será baseado em linhas para muitas aplicações) e a eficiência da largura de banda desde que TCP_NODELAY
ativada. Também com -tt
, ssh
define o IPQoS lowdelay
como oposto a throughput
. Você pode solucionar os dois com:
ssh -o IPQoS=throughput -tt host 'stty raw -echo; sudo cmd | cat' < <(cat)
Além disso, observe que isso significa que o comando remoto não pode detectar o final do arquivo em seu stdin e o stdout e o stderr do comando remoto são mesclados em um único fluxo.
Então, não é tão bom assim, afinal.
Se você um tem uma maneira de gerar um pseudo-terminal no host remoto (como com expect
, zsh
, socat
, perl
's IO::Pty
...), então seria melhor usar isso para criar o pseudo-terminal para anexar sudo
a (mas não para E / S) e use ssh
sem -t
.
Por exemplo, com 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'
Ou com script
(assumindo aqui a implementação de 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'
(assumindo (para ambos) que o shell de login do usuário remoto é semelhante ao Bourne).
Por padrão, SUDO está configurado para exigir um TTY. Ou seja, espera-se que o SUDO seja executado a partir de um shell de login. Você pode anular esse requisito adicionando a -t
opção à sua chamada SSH:
ssh -t someserver sudo somecommand
A -t
alocação de forças de uma pseudo-tty.
Se você deseja executar isso globalmente, modifique /etc/sudoers
para especificar !requiretty
. Isso pode ser feito por usuário, grupo ou nível abrangente.
Use o -t
sinalizador ssh
para forçar a alocação de tty.
$ ssh luci tty
not a tty
$ ssh luci -t tty
/dev/ttys003
$
-t
para forçar a alocação quandoPseudo-terminal will not be allocated because stdin is not a terminal.
Encontrei esse problema usando o Docker e o Centos 7. Acabei fazendo o seguinte:
yum install -y sudo
sed -i -e 's/Defaults requiretty.*/ #Defaults requiretty/g' /etc/sudoers
Encontrei este hack em https://hub.docker.com/r/liubin/fluentd-agent/~/dockerfile
Uma alternativa interessante é executar o FreeIPA ou o IdM para gerenciar centralmente seus usuários e regras de sudoer. Você pode criar regras de sudo e atribuir a opção
! requiretty
na regra. O comando será executado conforme o esperado. Você também terá os benefícios de gerenciar todos os servidores e usuários a partir de um único conjunto de configurações.
Eu tive o mesmo problema. No meu caso, a solução foram duas linhas
myscript=$(cat ssh_test.sh)
ssh -t user@host "$myscript"
Explicação:
Coloque os comandos que você deseja executar (incluindo comandos sudo) em um script, por exemplo, "ssh_test.sh".
Leia o script inteiro em uma variável chamada "myscript".
Invoque ssh com apenas um -t e forneça a variável em vez de um comando.
Antes disso, tive problemas ao usar combinações de leitura de stdin e heredocs
requiretty
em seus sudoers padrão. Ele será corrigido em versões mais recentes