sudo sans risque : autoriser un utilisateur à gérer un seul service
Karim, de l'équipe web, doit pouvoir redémarrer Apache et lire ses logs. Lui donner le mot de passe root ? Non. L'ajouter au groupe wheel ? Il deviendrait root sur tout le serveur. La bonne réponse est une règle sudoers précise. Encore faut-il l'écrire sans laisser de porte ouverte : voici les pièges que je montre en formation, et la règle que j'utilise en production.
Tous les exemples ci-dessous ont été testés avec sudo 1.9.15, la version livrée avec RHEL 10.
Le point de départ
On crée un fichier dédié, toujours avec visudo pour éviter de casser sudo sur une faute de frappe :
sudo visudo -f /etc/sudoers.d/audit-web
# QUI OÙ EN TANT QUE QUOI
karim ALL=(root) /usr/bin/journalctl -u httpd
Karim peut lancer sudo journalctl -u httpd. Mais dès qu'il tape sudo journalctl -u httpd --since today, sudo refuse. Pourquoi ?
Règle n°1 : des arguments dans la règle = correspondance exacte
Quand une règle précise des arguments, la commande doit les reproduire exactement, ni plus, ni moins.
| Règle | Ce que Karim peut lancer |
|---|---|
/usr/bin/journalctl -u httpd | uniquement journalctl -u httpd |
/usr/bin/journalctl "" | uniquement journalctl, sans aucun argument |
/usr/bin/journalctl | n'importe quels arguments : -u sshd, -u httpd -u sshd… |
/usr/bin/journalctl seul donne accès à tous les journaux du système.Le piège du *
Le réflexe naturel pour autoriser « plus d'options » est d'ajouter une étoile :
karim ALL=(root) /usr/bin/systemctl * httpd
Cela paraît sûr : seules les commandes qui finissent par httpd passent. Voici ce que sudo autorise réellement :
| Commande | Résultat |
|---|---|
systemctl restart httpd | ✅ autorisé |
systemctl edit httpd | ⚠️ autorisé : ouvre un éditeur en root |
systemctl stop sshd httpd | ⚠️ autorisé : arrête aussi SSH |
systemctl status httpd | ⚠️ autorisé : ouvre less en root |
Dans sudoers, * correspond à n'importe quelle suite de caractères, espaces compris. Il ne vérifie pas l'action, seulement la fin de la ligne. Même chose côté logs : avec /usr/bin/journalctl -u httpd *, Karim peut taper -u httpd -u sshd et lire les logs SSH. Et la forme sans argument, journalctl -u httpd, n'est plus autorisée : l'étoile attend quelque chose après.
La bonne solution : une expression régulière
Depuis sudo 1.9.10, des arguments qui commencent par ^ et finissent par $ sont traités comme une expression régulière. On peut enfin dire « exactement ces actions, sur exactement ce service » :
# /etc/sudoers.d/audit-web
Cmnd_Alias HTTPD_SVC = /usr/bin/systemctl ^(start|stop|restart|reload|enable|disable|is-active|is-enabled) httpd([.]service)?$, \
/usr/bin/systemctl ^status httpd([.]service)? --no-pager$
Cmnd_Alias HTTPD_LOGS = /usr/bin/journalctl ^-u httpd([.]service)?( --since (today|yesterday))?( --no-pager)?$
karim ALL=(root) NOEXEC: HTTPD_SVC, HTTPD_LOGS
Résultat, testé commande par commande :
| Commande | Résultat |
|---|---|
systemctl restart httpd / stop httpd.service | ✅ autorisé |
systemctl status httpd --no-pager | ✅ autorisé |
journalctl -u httpd --since today | ✅ autorisé |
systemctl edit httpd | ❌ refusé |
systemctl stop sshd httpd | ❌ refusé |
journalctl -u httpd -u sshd | ❌ refusé |
*. C'est plus long, mais tout aussi sûr.Le piège caché : le pager
journalctl et systemctl status affichent leur sortie dans less. Lancé par sudo, less tourne en root. Or less sait exécuter des commandes : il suffit de taper !bash pour obtenir un shell… root.
karim → sudo journalctl -u httpd → less (root) → !bash → shell root
Les versions récentes de systemd lancent le pager en mode « sécurisé » sous sudo, ce qui bloque cette évasion. Mais on ne bâtit pas sa sécurité sur un comportement par défaut. Deux protections, dans la règle elle-même :
NOEXEC:empêche le programme autorisé de lancer un autre programme (pager, shell, éditeur) ;--no-pagerimposé dans la regex : la sortie va directement au terminal, sansless.
Le même raisonnement vaut pour vi, less, find, awk, tar et beaucoup d'autres : tous peuvent ouvrir un shell. Le site GTFOBins les recense. Pour éditer un fichier système, autorisez sudoedit plutôt qu'un éditeur.
Plusieurs règles ? La dernière gagne
Quand plusieurs lignes correspondent à la même commande, sudo applique la dernière. Ces deux fichiers donnent donc des résultats opposés :
# Karim NE PEUT PAS arrêter httpd : la seconde ligne l'emporte
karim ALL=(root) /usr/bin/systemctl ^stop httpd$
karim ALL=(root) !/usr/bin/systemctl
# Karim PEUT arrêter httpd
karim ALL=(root) !/usr/bin/systemctl
karim ALL=(root) /usr/bin/systemctl ^stop httpd$
Les fichiers de /etc/sudoers.d/ sont lus par ordre alphabétique : un fichier zz-… peut annuler un fichier audit-….
Tester avant de livrer
Inutile de se connecter en Karim pour vérifier une règle :
# 1. La syntaxe
sudo visudo -cf /etc/sudoers.d/audit-web
# 2. Tout ce que Karim peut faire
sudo -l -U karim
# 3. Une commande précise : affiche son chemin si elle est autorisée, rien sinon
sudo -l -U karim /usr/bin/systemctl edit httpd
# 4. Les tentatives refusées
sudo journalctl _COMM=sudo --since today | grep karim
En résumé
- Une commande sans argument dans la règle autorise tous les arguments.
*ne vérifie que la forme générale de la ligne et accepte des espaces : évitez-le.- Préférez une regex
^…$(sudo ≥ 1.9.10, RHEL 10) ou une liste exacte (RHEL 9). - Ajoutez
NOEXEC:et--no-pagerpour fermer la porte du pager. - N'autorisez jamais
systemctl edit, un éditeur ou un pager en root. - Testez avec
sudo -l -Uavant de livrer.
Vous durcissez vos serveurs RHEL ?
J'audite vos règles sudo et vos accès, ou je forme vos équipes Linux aux bonnes pratiques de sécurité.
Besoin d'aide sur ce sujet ?
Une astuce Cloud & DevOps par mois
OpenShift, Kubernetes, Terraform, sécurité : un conseil concret tiré du terrain, directement dans votre boîte mail. Pas de spam.


