Aller au contenu
Administration Linux medium

Configurer sudoers et déléguer des droits Linux

21 min de lecture

Déléguer, c'est autoriser une personne à lancer une commande précise avec des privilèges élevés, et rien d'autre. Le fichier /etc/sudoers est l'endroit où cette frontière s'écrit : un développeur qui doit redémarrer nginx n'a besoin ni du mot de passe root, ni d'un compte partagé, ni d'un accès à rm. Vous allez apprendre à écrire une règle correcte, à la valider avec visudo avant qu'elle ne verrouille la machine, à la ranger dans /etc/sudoers.d/ et à vérifier ensuite qui peut réellement quoi.

Cette page traite de la configuration. Si vous cherchez simplement à lancer une commande privilégiée sur votre poste, à ouvrir un shell root ou à comprendre le groupe sudo, commencez par Utiliser sudo : exécuter une commande en root.

  • Écrire une règle sudoers (utilisateur hôte=(cible) commandes)
  • Éditer sudoers avec visudo sans vous verrouiller hors du système
  • Regrouper les règles avec User_Alias, Cmnd_Alias et Runas_Alias
  • Déléguer une commande sans mot de passe grâce à NOPASSWD, et connaître son coût
  • Auditer les droits réels avec sudo -lU <user> et les journaux système

Sans sudo, il n'existe que deux états : vous êtes root, ou vous ne l'êtes pas. Cette binarité pousse aux pires pratiques, le mot de passe root partagé dans un gestionnaire d'équipe, ou le compte de service utilisé par cinq personnes. Plus personne ne sait qui a lancé quoi, et le départ d'un collaborateur impose de tout changer.

sudo casse cette binarité en introduisant un troisième état : une identité nominative qui reçoit un sous-ensemble de privilèges. Le principe est celui du moindre privilège : n'accordez que ce qui est strictement nécessaire à la tâche, pour réduire la surface d'attaque autant que la surface d'erreur. Un compte compromis ne rend alors accessible que la poignée de commandes qui lui étaient déléguées.

Ce modèle repose sur trois questions auxquelles chaque règle répond : qui est autorisé, sous quelle identité la commande s'exécute, et quelles commandes exactement sont permises. Tout le reste de cette page consiste à répondre proprement à ces trois questions.

Une erreur de syntaxe dans /etc/sudoers n'est pas un incident bénin : sudo refuse alors le fichier entier et plus personne ne peut élever ses privilèges, y compris vous. Sur un serveur distant sans accès console, cela devient un incident de production. C'est la raison d'être de visudo : il ouvre une copie de travail, verrouille le fichier contre les éditions concurrentes et surtout contrôle la syntaxe avant de remplacer l'original.

Fenêtre de terminal
sudo visudo # édition de /etc/sudoers
sudo visudo -f /etc/sudoers.d/webops # édition d'un fichier dédié

Refusez l'habitude de nano /etc/sudoers, même « juste pour une ligne ». Pour contrôler un fichier sans l'éditer, par exemple après un déploiement automatisé, visudo -c valide l'ensemble de la configuration :

Fenêtre de terminal
sudo visudo -c
Résultat
/etc/sudoers: parsed OK
/etc/sudoers.d/README: parsed OK
/etc/sudoers.d/webops: parsed OK

Chaque fichier doit répondre parsed OK. Tant que cette commande renvoie une erreur, considérez que votre configuration est cassée et gardez impérativement un terminal root déjà ouvert à côté pour réparer.

Une règle sudoers tient sur une ligne et se lit en quatre morceaux. La comprendre, c'est pouvoir écrire n'importe quelle délégation sans copier un exemple au hasard sur un forum.

marc ALL = (root) /usr/bin/systemctl restart nginx
| | | |
| | | +-- les commandes autorisées
| | +------------------------ l'identité cible (« sous qui »)
| +------------------------------- l'hôte où la règle s'applique
+--------------------------------------- qui est autorisé

Le premier champ désigne toujours qui : un utilisateur (marc), un groupe préfixé de % (%webops), ou un User_Alias défini plus haut dans le fichier. Le champ hôte vaut presque toujours ALL : il n'a d'intérêt que si vous distribuez un sudoers commun à plusieurs machines. L'identité cible entre parenthèses indique sous quel compte la commande s'exécutera, (root) dans l'immense majorité des cas, et peut préciser un groupe avec (root:root). Enfin viennent les commandes, en chemin absolu.

Deux règles fondatrices en découlent, à graver avant d'écrire quoi que ce soit :

  • Le chemin doit être absolu. systemctl seul ne matche rien ; il faut /usr/bin/systemctl. Vérifiez le chemin réel avec command -v systemctl, il varie entre distributions.
  • La dernière règle qui matche gagne. Contrairement au réflexe « premier match » des pare-feux, sudo applique la dernière correspondance. Une règle permissive placée après une règle restrictive annule cette dernière.

Passé trois utilisateurs et cinq commandes, écrire une ligne par personne devient ingérable. sudoers propose pour cela des alias, des étiquettes que vous définissez et réutilisez. C'est le seul mécanisme de regroupement du format, avec les groupes système (%webops).

Trois types d'alias couvrent les besoins réels. Ils se définissent en tête de fichier, avant les règles qui les emploient :

AliasRegroupeExemple
User_AliasDes utilisateurs autorisésUser_Alias WEBOPS = marc, sophie
Cmnd_AliasDes commandes (chemins absolus)Cmnd_Alias NGINX_OPS = /usr/bin/systemctl reload nginx
Runas_AliasDes identités ciblesRunas_Alias DEPLOYER = deploy

Voici une délégation complète et cohérente : l'équipe web peut recharger et redémarrer nginx, lire les journaux du service, et lancer rsync sous l'identité technique deploy. Personne ne reçoit root.

/etc/sudoers.d/delegation
User_Alias WEBOPS = marc, sophie
Runas_Alias DEPLOYER = deploy
Cmnd_Alias NGINX_OPS = /usr/bin/systemctl reload nginx, /usr/bin/systemctl restart nginx
Cmnd_Alias LOGS = /usr/bin/journalctl -u nginx *
WEBOPS ALL=(root) NOPASSWD: NGINX_OPS, LOGS
WEBOPS ALL=(DEPLOYER) NOPASSWD: /usr/bin/rsync

Validez, puis vérifiez ce que le système a réellement compris de vos intentions, ce qui n'est pas toujours ce que vous croyez avoir écrit :

Fenêtre de terminal
sudo visudo -c -f /etc/sudoers.d/delegation
sudo -lU marc
Résultat
/etc/sudoers.d/delegation: parsed OK
User marc may run the following commands on serveur:
(root) NOPASSWD: /usr/bin/systemctl reload nginx, /usr/bin/systemctl restart nginx, /usr/bin/journalctl -u nginx *
(deploy) NOPASSWD: /usr/bin/rsync

Les alias ont été résolus : sudo affiche les commandes réelles, pas les étiquettes. Un %groupe système reste souvent préférable à un User_Alias quand les membres changent souvent : vous ajoutez le collaborateur au groupe avec usermod -aG sans jamais rouvrir sudoers.

Par défaut, une règle sudoers demande le mot de passe de l'appelant. Le tag NOPASSWD: lève cette demande pour les commandes qui suivent. Il est indispensable pour les scripts et les agents de CI qui n'ont aucun terminal pour saisir un mot de passe, et pratique pour une commande lancée cinquante fois par jour.

%webops ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx

Le membre du groupe exécute alors la commande sans aucune saisie, et seulement celle-là :

Fenêtre de terminal
sudo -n systemctl restart nginx # autorisé, aucun mot de passe
sudo -n systemctl stop nginx # non délégué
Résultat de la commande non déléguée
Sorry, user marc is not allowed to execute '/usr/bin/systemctl stop nginx' as root on serveur.

Le refus est net et tracé. C'est exactement le comportement recherché : restart est permis, stop ne l'est pas, alors que les deux commandes diffèrent d'un mot.

L'identité cible entre parenthèses n'est pas décorative, et c'est là que se niche l'erreur la plus fréquente. On croise souvent une règle de ce genre, censée laisser un développeur redémarrer le serveur web « sous le compte du serveur web » :

# Règle inopérante : ne la copiez pas
web_admin ALL=(www-data) /usr/bin/systemctl restart nginx

Elle échoue pour deux raisons distinctes. D'abord, elle ne porte pas le tag NOPASSWD: : le mot de passe sera demandé, contrairement à ce qu'affirment bien des tutoriels qui recopient cet exemple. Ensuite et surtout, systemctl restart s'adresse à systemd via D-Bus, et systemd exige que l'appelant soit root ou passe par une autorisation polkit. Exécutée sous www-data, la commande est rejetée :

Résultat réel
Failed to restart nginx.service: Interactive authentication required.

La cible correcte pour piloter un service est donc (root). L'identité cible autre que root garde tout son sens pour d'autres usages, par exemple lancer un script de déploiement sous un compte technique dédié, comme le (DEPLOYER) de l'exemple précédent.

Modifier /etc/sudoers directement pose un problème pratique : le fichier appartient au paquet de la distribution et chaque mise à jour majeure peut vous poser une question de conflit. La bonne pratique consiste à laisser ce fichier tranquille et à déposer vos règles dans des fichiers dédiés, un par usage, sous /etc/sudoers.d/. La dernière ligne du sudoers principal les inclut :

@includedir /etc/sudoers.d

La directive moderne est @includedir ; les formes #includedir et #include sont des alias historiques d'avant sudo 1.9.1 et fonctionnent encore. sudo lit tous les fichiers du répertoire, en ordre lexical, ce qui explique la convention de préfixe numérique (10-webops, 20-dba) pour maîtriser l'ordre d'application, souvenez-vous que la dernière règle qui matche gagne.

Deux contraintes non négociables pèsent sur ces fichiers, et elles sont la cause de la quasi-totalité des « ma règle ne fait rien » :

  • Les droits doivent être 0440 root:root. Un fichier trop permissif est ignoré, avec un avertissement au login. visudo -f pose les bons droits tout seul.
  • Le nom ne doit contenir ni point ni tilde final. sudo saute silencieusement tout fichier dont le nom contient un . ou finit par ~. Un drop-in nommé 10-webops.conf n'est jamais lu, et rien ne vous prévient.

Le second piège mérite un test systématique. Après avoir déposé un fichier, ne supposez pas qu'il est actif : demandez à sudo ce qu'il en pense avec sudo -lU <user>. Si la sortie n'a pas changé, le fichier est ignoré.

Comprendre l'ordre des vérifications permet de diagnostiquer un refus sans tâtonner. Quand un utilisateur tape une commande préfixée de sudo, le schéma suivant se déroule à chaque appel.

Fonctionnement de sudo

sudo lit sudoers et ses inclusions, puis cherche une règle qui corresponde simultanément à quatre critères : l'utilisateur appelant (directement, via un %groupe ou un User_Alias), l'hôte courant, l'identité cible demandée avec -u (root par défaut), et la commande avec ses arguments. Si plusieurs règles correspondent, la dernière l'emporte.

La décision qui en sort est binaire. Autorisé : sudo demande le mot de passe si NOPASSWD: est absent et si le timestamp de la session a expiré, puis exécute la commande sous l'identité cible. Refusé : sudo affiche Sorry, user ... is not allowed to execute ... et journalise la tentative. Ces deux issues laissent une trace nominative, ce qui fait de sudo un outil d'imputabilité autant que de délégation.

C'est ici que se corrige l'idée fausse la plus répandue : sudo -l ne liste que les droits de l'utilisateur qui l'appelle. Cette commande ne donne aucune vue d'ensemble du système et ne répond pas à la question « qui a des droits sudo sur cette machine ? ».

Pour inspecter le compte d'un autre utilisateur, il faut l'option -U, exécutée avec les privilèges d'administration :

Fenêtre de terminal
sudo -lU marc
Résultat
Matching Defaults entries for marc on serveur:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty
User marc may run the following commands on serveur:
(root) NOPASSWD: /usr/bin/systemctl reload nginx, /usr/bin/systemctl restart nginx

Pour obtenir la cartographie complète de la machine, aucune option magique n'existe : il faut itérer sudo -lU sur les comptes humains. La boucle suivante parcourt les UID de comptes réels et affiche la situation de chacun :

Fenêtre de terminal
getent passwd | awk -F: '$3>=1000 && $3<65534 {print $1}' | while read -r u; do
echo "--- $u"
sudo -lU "$u" | grep -E "may run|not allowed"
done
Résultat
--- ubuntu
User ubuntu may run the following commands on serveur:
--- web_admin
User web_admin is not allowed to run sudo on serveur.
--- marc
User marc may run the following commands on serveur:

Cette boucle donne la photo de l'état configuré. Pour l'état réel, autrement dit ce qui a effectivement été exécuté, les journaux prennent le relais. sudo journalise chaque appel, autorisé comme refusé :

Fenêtre de terminal
journalctl -t sudo --no-pager | tail -5
Résultat
Jul 12 08:39:12 serveur sudo[3594]: marc : PWD=/ ; USER=root ; COMMAND=/usr/bin/systemctl restart nginx
Jul 12 08:41:22 serveur sudo[3870]: marc : command not allowed ; PWD=/ ; USER=root ; COMMAND=/usr/bin/systemctl stop nginx

Chaque ligne nomme l'appelant (marc), l'identité cible (USER=root), la commande complète et le verdict : une tentative refusée apparaît explicitement en command not allowed. Sur les distributions qui utilisent encore un fichier texte, les mêmes lignes arrivent dans /var/log/auth.log (Debian/Ubuntu) ou /var/log/secure (RHEL). Une rafale de refus sur un compte est un signal à traiter immédiatement.

Une délégation mal écrite offre un chemin d'élévation vers root tout en donnant l'illusion de la restriction. Ces réflexes coûtent peu et évitent la faille.

Fuyez les jokers dans les chemins. Une règle %devs ALL=(root) /usr/bin/systemctl restart * autorise en réalité le redémarrage de n'importe quel service, y compris ceux dont dépend votre sécurité. Un * dans un chemin de commande est presque toujours une faille. Énumérez les commandes, même si la liste est longue.

Méfiez-vous des binaires qui savent lancer d'autres programmes. Déléguer vim, less, find, awk ou tar avec les privilèges root revient à déléguer root entier : tous permettent d'ouvrir un shell depuis leur interface. Le projet GTFOBins recense ces binaires et la manière exacte dont un attaquant s'en sert pour s'échapper de la restriction. Consultez-le avant d'ajouter un binaire à une règle : un sudo tar innocent est un shell root déguisé.

Préférez sudoedit à sudo vim quand il s'agit de modifier un fichier : l'édition se déroule alors avec vos privilèges sur une copie, et seul le remplacement final est privilégié. Déléguez à des groupes plutôt qu'à des personnes, pour que l'arrivée ou le départ d'un collaborateur ne demande jamais de rouvrir sudoers. Enfin, relisez les délégations périodiquement : une règle posée « pour dépanner » un mardi soir survit des années.

Les symptômes ci-dessous couvrent l'écrasante majorité des incidents sudoers. Le point commun de la plupart d'entre eux : la règle existe, mais sudo ne la lit pas ou ne la matche pas.

SymptômeCause probableSolution
user is not in the sudoers fileL'utilisateur n'est dans aucune règle ni dans %sudo/%wheelusermod -aG sudo <user> (Debian) ou wheel (RHEL), puis vérifier avec sudo -lU <user>
Plus aucun sudo ne fonctionne après une éditionErreur de syntaxe écrite sans visudoRéparer depuis une console root ou pkexec visudo, puis valider avec visudo -c
Un fichier de /etc/sudoers.d/ n'a aucun effetNom contenant un . ou finissant par ~, ou droits ≠ 0440Renommer sans point, chmod 0440, chown root:root
sudoers.d/... bad permissions au loginFichier non 0440 root:rootLe réécrire avec visudo -f /etc/sudoers.d/<fichier> (pose les bons droits)
La commande est refusée alors que la règle semble bonneChemin relatif ou différent du chemin réel du binaireComparer avec command -v <binaire>, écrire le chemin absolu
Interactive authentication requiredCommande systemctl lancée sous une identité cible autre que rootCibler (root) dans la règle
Une règle restrictive est ignoréeUne règle plus permissive matche après (la dernière gagne)Réordonner : placer le permissif avant le restrictif

Connaître l'origine de l'outil aide à comprendre pourquoi son fichier de configuration a cette allure si particulière : il est plus vieux que la plupart des distributions qui l'embarquent.

sudo est écrit vers 1980 par Bob Coggeshall et Cliff Spencer au département d'informatique de SUNY/Buffalo, pour un VAX-11/750 sous BSD. Le nom signifie « superuser do », littéralement « fais en tant que superutilisateur » ; la lecture « substitute user do », souvent répétée, est une rétro-étymologie postérieure. La première diffusion publique date de 1985, et le projet est maintenu par Todd C. Miller depuis 1994, aujourd'hui sous licence ISC. Cette longévité explique la compatibilité ascendante têtue du format sudoers, et donc la cohabitation de directives modernes (@includedir) avec leurs vieux alias (#includedir).

Écrire une règle sudoers sur le papier ne suffit pas : il faut la voir refuser ce qui n'est pas délégué. Le lab vous fait rédiger un drop-in dans /etc/sudoers.d/, le valider avec visudo, puis prouver avec sudo -lU que l'utilisateur ne peut lancer que la commande prévue, et rien d'autre.

Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

  • sudo délègue sans partager root : une identité nominative reçoit un sous-ensemble de commandes.
  • Format d'une règle : utilisateur hôte=(cible) commandes, avec des chemins absolus obligatoires.
  • Le premier champ est un utilisateur, un %groupe ou un User_Alias : il n'existe pas de rôle dans sudoers.
  • Toujours visudo : une erreur écrite directement dans sudoers verrouille tout sudo.
  • Drop-ins dans /etc/sudoers.d/ en 0440 root:root ; un nom avec un . ou finissant par ~ est ignoré silencieusement.
  • La dernière règle qui matche gagne : l'ordre compte, à l'inverse du réflexe « premier match ».
  • Pour piloter un service, la cible est (root) : sous un autre compte, systemd renvoie Interactive authentication required.
  • sudo -l ne montre que vos droits ; l'audit passe par sudo -lU <user> et les journaux.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn