Por que preciso de um tty para executar o sudo se eu posso sudo sem uma senha?

226

Eu configurei sudopara 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?

merlin2011
fonte

Respostas:

290

Provavelmente porque seu /etc/sudoersarquivo (ou qualquer outro arquivo incluído) possui:

Defaults requiretty

... o que sudoexige um TTY. Sabe-se que os sistemas Red Hat (RHEL, Fedora ...) exigem um TTY no sudoersarquivo 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 -tou -ttnas sshquais gera um pseudo-terminal no lado remoto, mas cuidado com o fato de ter vários efeitos

-ttdestina-se ao uso interativo. Ele coloca o terminal local no rawmodo para que você interaja com o terminal remoto. Isso significa que, se a sshE / 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, LFs serão convertidos em CRLFs ... (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 rawmodo. E estamos usando stty raw -echopara 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_NODELAYativada. Também com -tt, sshdefine o IPQoS lowdelaycomo 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 sudoa (mas não para E / S) e use sshsem -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).

Stéphane Chazelas
fonte
30

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 -topção à sua chamada SSH:

ssh -t someserver sudo somecommand

A -talocação de forças de uma pseudo-tty.

Se você deseja executar isso globalmente, modifique /etc/sudoerspara especificar !requiretty. Isso pode ser feito por usuário, grupo ou nível abrangente.

JRFerguson
fonte
5
Não, esse não é o padrão. É apenas a distribuição redhat do sudo que teve requirettyem seus sudoers padrão. Ele será corrigido em versões mais recentes
Stéphane Chazelas
1
@StephaneChazelas +1 por me esclarecer que é amplamente indígena da Red Hat e seus irmãos e outra ++, se eu puder, para o relatório de erros atual!
JRFerguson 01/04
18

Use o -tsinalizador sshpara forçar a alocação de tty.

$ ssh luci tty
not a tty
$ ssh luci -t tty
/dev/ttys003
$
Kyle Jones
fonte
Adicione um segundo -tpara forçar a alocação quandoPseudo-terminal will not be allocated because stdin is not a terminal.
Samveen 1/17/17
11

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

Martin Tapp
fonte
1
Essa resposta fez mais sentido para mim, usando o Docker e o CentOS 7 também. Foi fácil de entender, além de copiar / colar!
DaShaun
1

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.

strtluge
fonte
0

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

Gerry Hickman
fonte
-1

Encontrei essa pergunta ao pesquisar no Google e encontrei esse erro por um motivo completamente diferente.

Minha correção foi parar de chamar scripts de shell a jusante a partir sudodo meu script de shell pai, quando o script de shell pai já foi chamado com sudo.

entpnerd
fonte