Por que preciso de um tty para rodar o sudo se consigo sudo sem uma senha?

215

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 contornar isso?

    
por merlin2011 01.04.2014 / 21:12

7 respostas

281

Isso é provavelmente porque o arquivo /etc/sudoers (ou qualquer arquivo incluído) possui:

Defaults requiretty

... o que faz com que sudo exija um TTY. Sistemas Red Hat (RHEL, Fedora ...) são conhecidos por exigirem um TTY no arquivo sudoers 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 a alteração da configuração do servidor não for uma opção, como alternativa para essa configuração incorreta, você pode usar as opções -t ou -tt para ssh , o que gera um pseudo-terminal no lado remoto, mas tenha cuidado com os vários efeitos colaterais.

-tt destina-se ao uso interativo. Ele coloca o terminal local no modo raw para que você interaja com o terminal remoto. Isso significa que se ssh I / O não for de / para um terminal, isso terá efeitos colaterais. Por exemplo, toda a entrada será ecoada de volta, caracteres de terminal especiais ( ^? , ^C , ^U ) causarão processamento especial; na saída, LF s será convertido em CRLF s ... (consulte esta resposta para Por que este arquivo binário está sendo alterado? para mais detalhes.

Para minimizar o impacto, você poderia invocá-lo como:

ssh -tt host 'stty raw -echo; sudo ...' < <(cat)

O < <(cat) evitará a configuração do terminal local (se houver) no modo raw . E estamos usando stty raw -echo para definir a disciplina de linha do terminal remoto como passagem (efetivamente para que se comporte como o canal que seria usado em vez de um pseudo-terminal sem -tt , embora isso se aplique somente depois desse comando é executado, 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 irá para um terminal, isso ainda afetará seu buffering (que será baseado em linha para muitos aplicativos) e a eficiência da largura de banda, pois TCP_NODELAY está ativado. Também com -tt , ssh define o IPQoS como lowdelay em vez de throughput . Você poderia contornar ambos 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 fim do arquivo em seu stdin e que o stdout e o stderr do comando remoto são mesclados em um único fluxo.

Então, não é um bom trabalho depois de tudo.

Se você tiver uma maneira de gerar um pseudo-terminal no host remoto (como expect , zsh , socat , perl ' IO::Pty ...), então seria melhor usar isso para criar o pseudo-terminal para anexar sudo a (mas não para E / S) e usar 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 é parecido com Bourne).

    
por 01.04.2014 / 22:32
26

Por padrão, 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 derrotar este requisito adicionando a opção -t à sua chamada SSH:

ssh -t someserver sudo somecommand

O -t força a alocação de uma pseudo-tty.

Se você deseja realizar isso globalmente, modifique /etc/sudoers para especificar !requiretty . Isso pode ser feito por usuário, por grupo ou por todo o nível.

    
por 01.04.2014 / 21:25
17

Use o -t flag para ssh para forçar a alocação de tty.

$ ssh luci tty
not a tty
$ ssh luci -t tty
/dev/ttys003
$
    
por 01.04.2014 / 21:23
10

Eu 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 no link

    
por 21.03.2016 / 14:07
1

Uma alternativa interessante é executar o FreeIPA ou o IdM para gerenciar centralmente os usuários e as regras do sudoer. Você pode então criar regras 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 de um único conjunto de configurações.

    
por 06.06.2016 / 04:41
0

Eu tive o mesmo problema. No meu caso, a solução foi duas linhas

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

Explicação:

  • Coloque os comandos que você deseja executar (incluindo comandos do sudo) em um script, por exemplo, "ssh_test.sh".

  • Leia todo o script 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, me deparei com problemas usando combinações de leitura de stdin e usando heredocs

    
por 30.08.2018 / 14:46
-1

Encontrei essa pergunta enquanto pesquisava e encontrei esse erro por um motivo completamente diferente.

Minha correção foi parar de chamar scripts de shell downstream como sudo do meu script de shell pai, quando o script de shell pai já era chamado com sudo .

    
por 13.11.2017 / 20:58

Tags