Accueil / Blog

sudo sans risque : autoriser un utilisateur à gérer un seul service

Ismail Ait ZaidPar Ismail Ait Zaid··7 min de lecture

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ègleCe que Karim peut lancer
/usr/bin/journalctl -u httpduniquement journalctl -u httpd
/usr/bin/journalctl ""uniquement journalctl, sans aucun argument
/usr/bin/journalctln'importe quels arguments : -u sshd, -u httpd -u sshd…
Piège n°1 : une commande sans argument dans la règle autorise tous les arguments. /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 :

CommandeRé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 :

CommandeRé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é
Sur RHEL 9, sudo est en version 1.9.5 et ne connaît pas les regex. Listez alors chaque commande autorisée une par une, sans *. 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-pager imposé dans la regex : la sortie va directement au terminal, sans less.

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-pager pour fermer la porte du pager.
  • N'autorisez jamais systemctl edit, un éditeur ou un pager en root.
  • Testez avec sudo -l -U avant 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é.

Me contacter ← Tous les articles

Besoin d'aide sur ce sujet ?

Newsletter

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.