He configurado sudo
para ejecutar sin contraseña, pero cuando lo intento ssh 'sudo Foo'
, sigo recibiendo el mensaje de error sudo: sorry, you must have a tty to run sudo
.
¿Por qué sucede esto y cómo puedo solucionarlo?
He configurado sudo
para ejecutar sin contraseña, pero cuando lo intento ssh 'sudo Foo'
, sigo recibiendo el mensaje de error sudo: sorry, you must have a tty to run sudo
.
¿Por qué sucede esto y cómo puedo solucionarlo?
Respuestas:
Probablemente sea porque su /etc/sudoers
archivo (o cualquier archivo que incluya) tiene:
Defaults requiretty
... lo que hace que sudo
requiera un TTY. Se sabe que los sistemas Red Hat (RHEL, Fedora ...) requieren un TTY en el sudoers
archivo predeterminado . Eso no proporciona ningún beneficio de seguridad real y se puede eliminar de forma segura.
Red Hat ha reconocido el problema y se eliminará en futuras versiones.
Si cambiar la configuración del servidor no es una opción, como una solución alternativa para esa configuración incorrecta, puede usar las opciones -t
o que generan un pseudo terminal en el lado remoto, pero tenga cuidado de que tenga un número de lados efectos-tt
ssh
-tt
está destinado para uso interactivo. Pone el terminal local en raw
modo para que pueda interactuar con el terminal remoto. Eso significa que si la ssh
E / S no es de / a un terminal, tendrá efectos secundarios. Por ejemplo, toda la entrada se hizo eco de vuelta, caracteres terminales especiales ( ^?
, ^C
, ^U
) hará que el procesamiento especial; en la salida, LF
s se convertirá en CRLF
s ... (vea esta respuesta a ¿Por qué se cambia este archivo binario? para más detalles.
Para minimizar el impacto, puede invocarlo como:
ssh -tt host 'stty raw -echo; sudo ...' < <(cat)
Esto < <(cat)
evitará la configuración del terminal local (si lo hay) en raw
modo. Y lo estamos utilizando stty raw -echo
para establecer la disciplina de línea del terminal remoto a medida que pasa (efectivamente, para que se comporte como la tubería que se usaría en lugar de un pseudo-terminal sin -tt
, aunque eso solo se aplica después de ejecutar ese comando, por lo que necesita retrasar el envío de algo para la entrada hasta que eso suceda).
Tenga en cuenta que dado que la salida del comando remoto irá a un terminal, eso afectará su almacenamiento en búfer (que estará basado en líneas para muchas aplicaciones) y la eficiencia del ancho de banda ya que TCP_NODELAY
está activado. También con -tt
, ssh
establece el IPQoS en lowdelay
lugar de throughput
. Podrías evitar ambos con:
ssh -o IPQoS=throughput -tt host 'stty raw -echo; sudo cmd | cat' < <(cat)
Además, tenga en cuenta que significa que el comando remoto no puede detectar el final del archivo en su stdin y que stdout y stderr del comando remoto se fusionan en una sola secuencia.
Entonces, no es un buen trabajo después de todo.
Si usted ha conseguido una manera de generar un pseudo-terminal en el host remoto (como con expect
, zsh
, socat
, perl
's IO::Pty
...), entonces sería mejor utilizar eso para crear la pseudo-terminal para unir sudo
a (pero no para E / S), y uso ssh
sin -t
.
Por ejemplo, con 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'
O con script
(aquí asumiendo la implementación desde 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'
(suponiendo (para ambos) que el shell de inicio de sesión del usuario remoto es similar a Bourne).
Por defecto, SUDO está configurado para requerir un TTY. Es decir, se espera que SUDO se ejecute desde un shell de inicio de sesión. Puede anular este requisito agregando el -t
interruptor a su invocación SSH:
ssh -t someserver sudo somecommand
La -t
asignación de fuerzas de un pseudo-tty.
Si desea realizar esto globalmente, modifique /etc/sudoers
para especificar !requiretty
. Esto se puede hacer aa por usuario, por grupo o nivel global.
Use la -t
bandera ssh
para forzar la asignación de tty.
$ ssh luci tty
not a tty
$ ssh luci -t tty
/dev/ttys003
$
-t
para forzar la asignación cuandoPseudo-terminal will not be allocated because stdin is not a terminal.
Me encontré con este problema usando Docker y Centos 7. Terminé haciendo lo siguiente:
yum install -y sudo
sed -i -e 's/Defaults requiretty.*/ #Defaults requiretty/g' /etc/sudoers
Encontré este truco en https://hub.docker.com/r/liubin/fluentd-agent/~/dockerfile
Una alternativa interesante es ejecutar FreeIPA o IdM para administrar sus usuarios y reglas de sudoer de forma centralizada. Luego puede crear reglas de sudo y asignar la opción
! requiretty
en la regla El comando se ejecutará como se esperaba. También tendrá los beneficios de administrar todos los servidores y usuarios desde un único conjunto de configuraciones.
Tuve el mismo problema. En mi caso, la solución fue dos líneas.
myscript=$(cat ssh_test.sh)
ssh -t user@host "$myscript"
Explicación:
Coloque los comandos que desea ejecutar (incluidos los comandos sudo) en un script, por ejemplo, "ssh_test.sh".
Lea todo el script en una variable llamada "myscript".
Invoque ssh con solo uno -t y proporcione la variable en lugar de un comando.
Antes de esto, me encontré con problemas al usar combinaciones de lectura de stdin y usar heredocs
requiretty
en sudoers por defecto. Se solucionará en versiones más recientes