Le mot de passe sudo est-il envoyé en clair ?
Pas sur le réseau. Tout ce qui passe dans une session SSH est chiffré, y compris ce que vous tapez à une invite sudo. Le mot de passe est déchiffré sur le serveur, comme il le faut pour que sudo le vérifie : un serveur compromis peut donc le capturer. C'est une raison de ne pas réutiliser ce mot de passe ailleurs.
La méthode normale : ssh -t
sudo a besoin d'un terminal pour demander un mot de passe, et une commande distante n'en reçoit aucun par défaut :
$ 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'erreur suggère -S, et c'est là que les gens se trompent. La solution simple est -t, qui demande un terminal :
ssh -t user@server 'sudo whoami'
Vous obtenez l'invite normale, rien n'est affiché à l'écran, et rien ne figure dans une ligne de commande.
Ce qui fuit avec sudo -S
Voici le schéma à éviter :
ssh user@server 'echo mypassword | sudo -S systemctl restart myapp'
Le mot de passe fait maintenant partie d'une commande, et apparaît donc à trois endroits :
- La liste des processus du serveur. Pendant l'exécution de la commande, un autre compte sans privilèges du serveur de test voyait ceci avec un simple
ps:user bash -c echo mypassword | sudo -S -p "" sleep 3. - La liste des processus de votre machine. Tout le texte est un argument de
ssh,psl'y affiche donc aussi. - L'historique de votre shell local, si vous l'avez tapé, et tout script ou journal de CI qui le contient.
Si vous devez vraiment alimenter sudo depuis un script
Lisez le mot de passe sans écho et envoyez-le sur l'entrée standard, pour qu'il ne devienne jamais un argument :
read -rs SUDO_PW
printf '%s\n' "$SUDO_PW" | ssh user@server 'sudo -S -p "" whoami'
unset SUDO_PW
printf est une commande interne du shell : elle ne lance pas de processus que ps pourrait afficher. Dans le même test, l'autre compte ne voyait que sudo -S -p sleep 3. -p "" retire l'invite de la sortie. sudo utilise ici l'entrée standard pour le mot de passe, la commande distante ne doit donc pas avoir besoin de sa propre entrée.
Pour l'automatisation : NOPASSWD pour une commande exacte
Un script ne devrait détenir aucun mot de passe. Autorisez seulement ce dont il a besoin :
# /tmp/deploy.sudoers
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart myapp, /usr/bin/journalctl -u myapp -n 100 --no-pager
Vérifiez le fichier avant de l'installer, car un fichier sudoers cassé peut vous verrouiller hors de 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
Utilisez-le ensuite, avec -n pour qu'une non-correspondance échoue tout de suite au lieu de rester bloquée à attendre un mot de passe :
$ 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
Listez ce qu'un compte peut exécuter avec sudo -l. Quatre pièges :
- Une commande sans arguments dans la règle autorise n'importe quels arguments. Avec
/usr/bin/idseul dans la règle,sudo -n /usr/bin/idetsudo -n /usr/bin/id -use sont exécutés dans notre test. Écrivez les arguments que vous voulez. - Les noms de fichiers contenant un point sont ignorés.
/etc/sudoers.d/deploy.confn'a eu aucun effet dans notre test, alors que le même fichier nommédeployfonctionnait. - Certaines commandes peuvent lancer un shell. Les éditeurs, les paginateurs,
find -execettarpeuvent exécuter d'autres programmes en root : en autoriser un peut donc revenir à tout autoriser. C'est pourquoi la règle ci-dessus a--no-pager: sans cela, journalctl peut ouvrir un paginateur. - Les jokers correspondent aussi aux espaces. Le manuel de sudoers avertit que les jokers dans les arguments correspondent à n'importe quel caractère, espaces compris, et peuvent donc correspondre à plus d'arguments que prévu.
Combien de temps sudo se souvient de vous
Par défaut, sudo ne redemande pas pendant 5 minutes, et l'enregistrement est séparé pour chaque terminal. Dans le test, une session ssh -t a exécuté un second sudo -n whoami sans invite. Pour y mettre fin plus tôt, lancez sudo -k. Pour demander à chaque fois pour un compte, ajoutez ceci avec visudo :
Defaults:deploy timestamp_timeout=0
Un shell root resté ouvert est là où arrivent la plupart des erreurs. Voir comment éviter les erreurs sur les serveurs de production.
sudo -A et askpass
Avec -A, sudo exécute le programme nommé dans SUDO_ASKPASS et lit le mot de passe dans sa sortie :
SUDO_ASKPASS=$HOME/bin/askpass sudo -A whoami
Cela garde le mot de passe hors de la liste des processus, mais l'assistant doit le tirer de quelque part. Sur un serveur sans session graphique, c'est en général un fichier, comme dans notre test : le secret se retrouve donc sur le disque. Une règle NOPASSWD étroite est normalement la meilleure réponse.
Ansible
Utilisez --ask-become-pass (-K) pour être invité à le saisir, ou gardez ansible_become_password dans un fichier chiffré avec Ansible Vault. Ne le passez pas avec -e en ligne de commande, car cela le met dans la liste des processus et dans votre historique comme n'importe quel autre argument.
Une règle NOPASSWD pour quelques commandes ne fonctionne pas avec Ansible. Sa documentation dit que l'élévation de privilèges ne peut pas être limitée à certaines commandes, car les modules s'exécutent depuis un fichier temporaire dont le nom change à chaque fois. Elle suggère d'utiliser un compte séparé sans cette contrainte.
Questions
Le mot de passe sudo passe-t-il en clair sur SSH ?
Non. Tout ce qui passe dans une session SSH est chiffré, y compris ce que vous tapez à l'invite de sudo. Il est déchiffré sur le serveur, qui doit le vérifier.
Pourquoi ssh dit qu'un terminal est requis pour lire le mot de passe ?
Une commande distante n'a pas de terminal par défaut, et sudo en a besoin pour demander le mot de passe. Ajoutez -t, comme dans ssh -t user@server 'sudo command'.
NOPASSWD est-il sûr pour les scripts ?
C'est plus sûr qu'un mot de passe stocké si la règle désigne une seule commande précise avec ses arguments. Évitez les éditeurs, les pagers et les programmes capables de lancer un shell.
Sources
- Manuel de sudo(8)
- Manuel de sudoers(5)
- Manuel de visudo(8)
- Understanding privilege escalation, documentation Ansible