La password di sudo viaggia in chiaro?
Non sulla rete. Tutto in una sessione SSH è cifrato, compreso ciò che digiti al prompt di sudo. La password viene decifrata sul server, come deve essere perché sudo la controlli, quindi un server compromesso può catturarla. È un motivo per non riusare quella password altrove.
Il modo normale: ssh -t
sudo ha bisogno di un terminale per chiedere una password, e un comando remoto di default non ne riceve uno:
$ ssh user@server 'sudo whoami'
sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper
sudo: a password is required
L'errore suggerisce -S, ed è qui che si sbaglia. La soluzione semplice è -t, che chiede un terminale:
ssh -t user@server 'sudo whoami'
Ottieni il prompt normale, niente viene mostrato a schermo e niente finisce in una riga di comando.
Cosa trapela con sudo -S
Ecco lo schema da evitare:
ssh user@server 'echo mypassword | sudo -S systemctl restart myapp'
La password ora fa parte di un comando, quindi compare in tre posti:
- L'elenco dei processi sul server. Mentre il comando girava, un altro account senza privilegi sul server di prova ha visto questo con un semplice
ps:user bash -c echo mypassword | sudo -S -p "" sleep 3. - L'elenco dei processi sulla tua macchina. L'intero testo è un argomento di
ssh, quindipslo mostra anche lì. - La cronologia della tua shell locale, se l'hai digitato, e qualsiasi script o log di CI che lo contenga.
Se proprio devi dare la password a sudo da uno script
Leggi la password senza eco e inviala dallo standard input, così non diventa mai un argomento:
read -rs SUDO_PW
printf '%s\n' "$SUDO_PW" | ssh user@server 'sudo -S -p "" whoami'
unset SUDO_PW
printf è un builtin della shell, quindi non avvia un processo che ps possa mostrare. Nella stessa prova l'altro account vedeva solo sudo -S -p sleep 3. -p "" toglie il prompt dall'output. Qui sudo usa lo standard input per la password, quindi il comando remoto non deve aspettarsi input proprio.
Per l'automazione: NOPASSWD per un solo comando esatto
Uno script non dovrebbe contenere affatto una password. Consenti solo ciò che gli serve:
# /tmp/deploy.sudoers
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart myapp, /usr/bin/journalctl -u myapp -n 100 --no-pager
Controlla il file prima di installarlo, perché un file sudoers rotto può chiuderti fuori da sudo:
sudo visudo -cf /tmp/deploy.sudoers
sudo install -m 0440 -o root -g root /tmp/deploy.sudoers /etc/sudoers.d/deploy
sudo visudo -c
Poi usalo, con -n così una mancata corrispondenza fallisce subito e non resta in attesa di una password:
$ ssh deploy@server 'sudo -n /usr/bin/systemctl restart myapp'
$ ssh deploy@server 'sudo -n /usr/bin/systemctl stop myapp'
sudo: a password is required
Elenca ciò che un account può eseguire con sudo -l. Quattro trappole:
- Un comando senza argomenti nella regola consente qualsiasi argomento. Con il solo
/usr/bin/idnella regola, nel nostro test hanno funzionato siasudo -n /usr/bin/idsiasudo -n /usr/bin/id -u. Scrivi gli argomenti che intendi. - I nomi di file con un punto vengono ignorati.
/etc/sudoers.d/deploy.confnon ha avuto effetto nel nostro test, mentre lo stesso file chiamatodeployha funzionato. - Alcuni comandi possono avviare una shell. Editor, pager,
find -execetarpossono eseguire altri programmi come root, quindi consentirne uno può equivalere a consentire tutto. Per questo la regola qui sopra ha--no-pager: senza, journalctl può aprire un pager. - I caratteri jolly corrispondono anche agli spazi. Il manuale di sudoers avverte che i caratteri jolly negli argomenti corrispondono a qualsiasi carattere, spazi compresi, quindi possono corrispondere a più argomenti di quelli previsti.
Per quanto tempo sudo si ricorda di te
Per impostazione predefinita sudo non richiede la password per 5 minuti, e il ricordo è separato per ogni terminale. Nella prova, una sessione ssh -t ha eseguito un secondo sudo -n whoami senza richiesta. Per terminarlo prima, esegui sudo -k. Per chiedere la password ogni volta a un solo account, aggiungi questo con visudo:
Defaults:deploy timestamp_timeout=0
Una shell di root lasciata aperta è dove capitano più sviste. Vedi come evitare errori sui server di produzione.
sudo -A e askpass
Con -A, sudo esegue il programma indicato in SUDO_ASKPASS e legge la password dal suo output:
SUDO_ASKPASS=$HOME/bin/askpass sudo -A whoami
Tiene la password fuori dall'elenco dei processi, ma l'helper deve ottenerla da qualche parte. Su un server senza sessione grafica, di solito significa un file, come nel nostro test, quindi il segreto ora sta su disco. Una regola NOPASSWD ristretta è in genere la risposta migliore.
Ansible
Usa --ask-become-pass (-K) per ricevere una richiesta, oppure tieni ansible_become_password in un file cifrato con Ansible Vault. Non passarla con -e sulla riga di comando, perché finisce nell'elenco dei processi e nella cronologia come qualsiasi altro argomento.
Una regola NOPASSWD per pochi comandi non funziona con Ansible. La sua documentazione dice che l'escalation dei privilegi non può essere limitata a certi comandi, perché i moduli vengono eseguiti da un file temporaneo il cui nome cambia ogni volta. Suggerisce di usare un account separato senza questo vincolo.
Domande
La password di sudo passa in chiaro su SSH?
No. Tutto quello che passa in una sessione SSH è cifrato, compreso ciò che digiti al prompt di sudo. Viene decifrata sul server, che deve controllarla.
Perché ssh dice che serve un terminale per leggere la password?
Un comando remoto di base non riceve un terminale, e sudo ne ha bisogno per chiedere la password. Aggiungi -t, come in ssh -t user@server 'sudo command'.
NOPASSWD è sicuro per gli script?
È più sicuro di una password salvata quando la regola indica un solo comando preciso con i suoi argomenti. Evita editor, pager e altri programmi che possono avviare una shell.
Fonti
- Manuale di sudo(8)
- Manuale di sudoers(5)
- Manuale di visudo(8)
- Understanding privilege escalation, documentazione di Ansible