Ho configurato sudo
per funzionare senza una password, ma quando provo a ssh 'sudo Foo'
ottenere ancora il messaggio di errore sudo: sorry, you must have a tty to run sudo
.
Perché questo accade e come posso aggirarlo?
Ho configurato sudo
per funzionare senza una password, ma quando provo a ssh 'sudo Foo'
ottenere ancora il messaggio di errore sudo: sorry, you must have a tty to run sudo
.
Perché questo accade e come posso aggirarlo?
Risposte:
Questo probabilmente perché il tuo /etc/sudoers
file (o qualsiasi altro file incluso) ha:
Defaults requiretty
... il che rende sudo
necessario un TTY. È noto che i sistemi Red Hat (RHEL, Fedora ...) richiedono un TTY nel sudoers
file predefinito . Ciò non offre alcun reale vantaggio in termini di sicurezza e può essere rimosso in modo sicuro.
Red Hat ha riconosciuto il problema e verrà rimosso nelle versioni future.
Se la modifica della configurazione del server non è un'opzione, come soluzione per quella errata configurazione, è possibile utilizzare le opzioni -t
o -tt
a ssh
cui viene generato uno pseudo-terminale sul lato remoto, ma attenzione che ha un certo numero di lati effetti.
-tt
è pensato per l'uso interattivo. Mette il terminale locale in raw
modalità in modo da interagire con il terminale remoto. Ciò significa che se l' ssh
I / O non proviene da / verso un terminale, ciò avrà effetti collaterali. Ad esempio, tutti gli input verrà eco indietro, caratteri speciali terminali ( ^?
, ^C
, ^U
) causerà elaborazione speciale; sull'output, LF
s verrà convertito in CRLF
s ... (vedere questa risposta a Perché questo file binario viene modificato? per maggiori dettagli.
Per ridurre al minimo l'impatto, è possibile invocarlo come:
ssh -tt host 'stty raw -echo; sudo ...' < <(cat)
Il < <(cat)
eviterà l'impostazione del terminale locale (se presente) in raw
modalità. E stiamo usando stty raw -echo
per impostare la disciplina di linea del terminale remoto come pass through (in modo efficace, quindi si comporta come la pipe che verrebbe utilizzata al posto di uno pseudo-terminale senza -tt
, anche se questo si applica solo dopo l'esecuzione di quel comando, quindi è necessario ritardare l'invio di qualcosa per l'input fino a quando ciò accade).
Si noti che poiché l'output del comando remoto verrà indirizzato a un terminale, ciò influenzerà comunque il suo buffering (che sarà basato su linea per molte applicazioni) e l'efficienza della larghezza di banda poiché TCP_NODELAY
è attiva. Inoltre -tt
, ssh
imposta IPQoS su lowdelay
opposto a throughput
. Puoi aggirare entrambi con:
ssh -o IPQoS=throughput -tt host 'stty raw -echo; sudo cmd | cat' < <(cat)
Inoltre, si noti che significa che il comando remoto non è in grado di rilevare la fine del file sul suo stdin e che lo stdout e lo stderr del comando remoto vengono uniti in un singolo flusso.
Quindi, dopotutto, non è un buon lavoro.
Se hai un ottenuto un modo per generare una pseudo-terminale sul host remoto (come con expect
, zsh
, socat
, perl
s' IO::Pty
...), allora sarebbe meglio usare che per creare la pseudo-terminale da allegare sudo
a (ma non per I / O) e utilizzare ssh
senza -t
.
Ad esempio, 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
(qui assumendo l'implementazione da 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'
(supponendo (per entrambi) che la shell di accesso dell'utente remoto sia simile a Bourne).
Per impostazione predefinita, SUDO è configurato per richiedere un TTY. Cioè, SUDO dovrebbe essere eseguito da una shell di login. È possibile annullare questo requisito aggiungendo il -t
passaggio alla chiamata SSH:
ssh -t someserver sudo somecommand
L' -t
assegnazione forze di una pseudo-tty.
Se si desidera eseguire questa operazione a livello globale, modificare /etc/sudoers
per specificare !requiretty
. Questo può essere fatto aa per utente, per gruppo o livello onnicomprensivo.
Usa la -t
bandiera ssh
per forzare l'allocazione di tty.
$ ssh luci tty
not a tty
$ ssh luci -t tty
/dev/ttys003
$
-t
per forzare l'allocazione quandoPseudo-terminal will not be allocated because stdin is not a terminal.
Ho riscontrato questo problema utilizzando Docker e Centos 7. Ho finito per fare quanto segue:
yum install -y sudo
sed -i -e 's/Defaults requiretty.*/ #Defaults requiretty/g' /etc/sudoers
Ho trovato questo trucco su https://hub.docker.com/r/liubin/fluentd-agent/~/dockerfile
Un'alternativa interessante è eseguire FreeIPA o IdM per gestire centralmente i tuoi utenti e le regole sudoer. È quindi possibile creare regole sudo e assegnare l'opzione
! requiretty
nella regola. Il comando verrà quindi eseguito come previsto. Avrai anche i vantaggi di gestire tutti i server e gli utenti da un unico set di configurazioni.
Ho avuto lo stesso problema. Nel mio caso, la soluzione era di due righe
myscript=$(cat ssh_test.sh)
ssh -t user@host "$myscript"
Spiegazione:
Inserire i comandi che si desidera eseguire (inclusi i comandi sudo) in uno script, ad esempio "ssh_test.sh".
Leggi l'intero script in una variabile chiamata "myscript".
Richiamare ssh con solo uno -t e fornire la variabile invece di un comando.
Prima di questo, mi sono imbattuto in problemi usando combinazioni di lettura da stdin e usando heredocs
Ho trovato questa domanda mentre cercavamo su Google e ho riscontrato questo errore per una ragione completamente diversa.
La mia correzione era quella di smettere di chiamare script shell downstream come sudo
dal mio script shell genitore, quando lo script shell genitore era già stato chiamato con sudo
.
requiretty
nei suoi sudoer predefiniti. Sarà risolto nelle versioni più recenti