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.


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
echodevant pour voir en quoi un glob se développe :echo rm -rf /tmp/app/*. Retirez ensuite leecho. - Enchaînez avec
&&, pas avec;. Aveccd /var/app/tmp && rm -rf ./*, uncdqui é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 quandDIRest vide, alors qu'un simple"$DIR/"deviendrait/.set -uen haut d'un script arrête aussi sur les variables non définies. - Déplacez d'abord, supprimez plus tard. Un
mvvers un dossier d'attente peut s'annuler. Unrm, 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
| Commande | Aperçu |
|---|---|
| rsync | rsync -an --delete --itemize-changes src/ dst/ |
| find | find . -name '*.tmp' -print d'abord, puis remplacez -print par -delete |
| git clean | git clean -n |
| apt-get | apt-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
- Manuel GNU coreutils : rm et le traitement spécial de /
- Manuel de Bash : syntaxe du fichier d'initialisation de Readline
- tmux(1), manuel OpenBSD
- ssh_config(5), manuel OpenBSD