Comment éviter de lancer des commandes sur le mauvais serveur

Rendez la production impossible à confondre : mettez un prompt rouge dans PS1 sur chaque serveur de production, et colorez aussi la barre d'état tmux et le terminal. Prenez ensuite des habitudes qui rattrapent le faux pas : faites d'abord un dry run, listez un glob avant de le supprimer, écrivez "${DIR:?}" dans les scripts, et gardez le collage protégé (bracketed paste) activé. Cela réduit les erreurs sans les rendre impossibles : les sauvegardes restent indispensables.

Mis à jour le . Le prompt, les garde-fous de rm, les dry runs, les couleurs de la barre tmux et le collage protégé ont été exécutés sous Debian 13 dans un conteneur jetable (bash 5.2, GNU coreutils 9.7, tmux 3.5), via SSH depuis macOS.

Un prompt rouge en production

La plupart des erreurs de serveur viennent de deux terminaux qui se ressemblent. Le prompt est ce que vous lisez juste avant d'appuyer sur Entrée : changez-le donc. Ajoutez ceci à la fin de ~/.bashrc sur le serveur. Cela doit aller à la fin, car le .bashrc de la distribution définit PS1 plus haut et écraserait votre ligne :

PS1='\[\e[1;37;41m\] PRODUCTION \[\e[0m\] \u@\h:\w\$ '

Cela affiche PRODUCTION en blanc sur rouge, puis l'utilisateur, l'hôte et le dossier habituels. Les \[ et \] indiquent à bash que les codes de couleur n'occupent aucune largeur, si bien que les longues commandes se replient correctement.

Ajoutez la même ligne à /root/.bashrc : dans notre test, sudo -i n'a affiché l'étiquette rouge que parce que ce fichier l'avait aussi. Pour la préproduction, utilisez du jaune avec \e[1;30;43m. Cela ne fonctionne que pour bash interactif : les autres shells ont besoin de leur propre réglage.

Terminal sur iPhone avec une étiquette Production dans le titre, affichant une boîte de dialogue qui demande Run this on production? avant une suppression récursive forcée, avec les boutons Cancel et Run itTerminal sur iPhone avec une étiquette Production dans le titre, affichant une boîte de dialogue qui demande Run this on production? avant une suppression récursive forcée, avec les boutons Cancel et Run it

Colorer la barre tmux et le terminal

Si vous utilisez tmux sur le serveur, colorez sa barre d'état, dans le ~/.tmux.conf de ce serveur :

set -g status-style bg=red,fg=white,bold
set -g status-left " PRODUCTION "

Vérifiez que la configuration est chargée avec tmux show -g status-style.

Sur votre propre machine, la plupart des applications de terminal peuvent ouvrir un hôte dans un profil séparé. Donnez à la production une fenêtre à fond rouge sombre. Vous pouvez aussi laisser votre configuration SSH régler la couleur, dans les terminaux qui prennent en charge la séquence OSC 11 :

Host prod-*
    PermitLocalCommand yes
    LocalCommand printf '\033]11;#400000\007'

La couleur ne revient pas d'elle-même à la déconnexion, et la prise en charge varie : essayez d'abord dans votre terminal.

Avec beaucoup de serveurs, des noms clairs et des groupes aident autant que les couleurs : voir comment gérer de nombreux serveurs SSH.

Supprimer des fichiers en sécurité

rm de GNU refuse déjà le pire cas :

$ rm -rf /
rm: it is dangerous to operate recursively on '/'
rm: use --no-preserve-root to override this failsafe

Cela ne protège que le / littéral. Dans rm -rf /*, le shell développe d'abord l'étoile : rm reçoit alors /bin, /etc et le reste, et la vérification ne s'applique pas. Une espace en trop dans rm -rf /var/app /* produit ce résultat par accident. Ces habitudes aident davantage :

  • Regardez avant de supprimer. Mettez echo devant pour voir en quoi un glob se développe : echo rm -rf /tmp/app/*. Retirez ensuite le echo.
  • Enchaînez avec &&, pas avec ;. Avec cd /var/app/tmp && rm -rf ./*, un cd qui échoue arrête tout. Avec ;, la suppression s'exécute dans le dossier où vous vous trouvez.
  • Protégez les variables dans les scripts. rm -rf "${DIR:?}/" s'arrête avec une erreur quand DIR est vide, alors qu'un simple "$DIR/" deviendrait /. set -u en haut d'un script arrête aussi sur les variables non définies.
  • Déplacez d'abord, supprimez plus tard. Un mv vers un dossier d'attente peut s'annuler. Un rm, non.
  • Utilisez rm -I. Il demande une confirmation avant de supprimer plus de trois fichiers ou de supprimer récursivement. Ne rien répondre ne supprime rien, comme dans notre test.
  • Utilisez --preserve-root=all. Il refuse aussi un dossier situé sur un autre système de fichiers que son parent, donc il refuserait un disque monté : rm: skipping '/dev/shm', since it's on a different device.

Les deux derniers peuvent aller dans un alias sur le serveur, alias rm='rm -I --preserve-root=all'. Les alias ne s'appliquent qu'aux shells interactifs, pas aux scripts ni à sudo rm, et ces options n'existent que dans GNU.

Dry run d'abord

CommandeAperçu
rsyncrsync -an --delete --itemize-changes src/ dst/
findfind . -name '*.tmp' -print d'abord, puis remplacez -print par -delete
git cleangit clean -n
apt-getapt-get -s remove package

Avec SQL, lancez d'abord BEGIN;, puis l'instruction, vérifiez le nombre de lignes, et terminez par COMMIT; ou ROLLBACK;. Cela ne couvre pas les instructions que votre base de données valide d'elle-même. MySQL le fait avec les modifications de table, par exemple.

Coller plusieurs lignes

Dans un terminal, un saut de ligne dans un texte collé agit comme Entrée : un collage peut donc exécuter des commandes avant que vous les ayez lues. Le collage protégé (bracketed paste) règle cela. Le terminal marque le texte collé, et le shell l'insère sans rien exécuter. Nous avons collé deux lignes echo dans bash via tmux :

  • Avec la fonction activée, les deux lignes restaient au prompt et rien ne s'exécutait avant Entrée.
  • Avec la fonction désactivée, la première ligne s'est exécutée dès qu'elle a été collée.

Elle est activée par défaut dans les versions actuelles de bash. Vérifiez avec cette commande dans un shell interactif :

bind -v | grep bracketed-paste

Si elle affiche off, ajoutez set enable-bracketed-paste on à ~/.inputrc. Cela n'aide que là où le programme le demande. Coller dans un programme qui ne le demande pas, ou dans un vieux shell, exécute toujours ligne par ligne.

Ce que cela ne peut pas faire

La couleur du prompt n'aide que si vous la regardez. Elle ne protège ni un script, ni une tâche cron, ni une commande lancée avec ssh server 'command', qui n'affiche jamais de prompt. Les alias peuvent être contournés, et rien de tout cela n'empêche une erreur dans les arguments d'une commande que vous vouliez bien lancer.

Gardez donc les protections plus larges : des sauvegardes testées, des comptes et des clés distincts pour la production, et le minimum de sudo nécessaire à chacun. Voir sudo via SSH pour des règles précises.

Questions

Comment mettre le prompt bash en rouge sur un serveur de production ?

Définissez PS1 avec un code couleur à fond rouge à la fin de ~/.bashrc sur ce serveur, et dans /root/.bashrc pour sudo -i. À la fin, pour que le PS1 de la distribution ne l'écrase pas.

rm -rf / fonctionne-t-il encore sous Linux ?

Le rm de GNU refuse le / littéral, sauf avec --no-preserve-root. Il ne protège pas rm -rf /*, car le shell remplace d'abord l'étoile par tous les dossiers de premier niveau.

Comment voir ce qu'une commande va supprimer avant de la lancer ?

Mettez echo devant pour voir ce que donne un motif, ou utilisez l'option d'essai : rsync -n, git clean -n, ou find avec -print avant -delete.

Sources

Autres guides : Sécuriser un serveur

Tous les guides