Cela va faire bientôt quinze ans que j’utilise des systèmes UNIX, que ce soit GNU/Linux ou Mac OS. Depuis tout ce temps, je me sers de la commande sudo pour bon nombre de tâches d’administration de mes machines. Ayant toujours été administrateur de mes propres machines, je n’ai jamais pris le temps de me pencher sur la gestion des droits en détail: C’moi l’patron, j’fais c’que j’veux.

Sauf que voilà, dans mon travail, j’administre des serveurs. Je les installe, les maintiens, les remplace. Plus récemment même, avec l’avènement du cloud ☁️ et de l’infrastructure as code, je les provisionne et programme leur (dé)commissionnement automatique. Je ne suis plus le patron, je ne fais plus ce que je veux.

Cet article est un pense-bête pour le moi du futur à propos de comment donner uniquement les droits nécessaires et suffisants à chaque groupe et utilisateur via la configuration de sudo.

Les règles pour permettre à un utilisateur ou un membre d’un groupe d’appeler une commande avec sudo sont à inscrire au format texte dans le dossier /etc/sudoers.d/. Une bonne pratique consiste à créer un fichier par groupe ou par utilisateur.

La syntaxe

Chaque ligne de chacun de ces fichiers est de la forme suivante:

$USERS $HOSTS=($RUN_AS) $OPTIONS: $COMMANDS

Autrement dit: $USER peut lancer $COMMANDS en tant que $AS sur $HOST.

L’exemple typique du C’moi l’patron, j’fais c’que j’veux se traduit donc pas : user ALL=(ALL:ALL) NOPASSWD: ALL. L’utilisateur user peut sans entre de mot de passe lancer toutes les commandes en se faisant passer pour n’importe qui et ce n’importe où.

Users or groups

Ce que j’appelle ci-dessus $USERS est défini de manière plus formelle comme User_List ::= User | User ',' User_List. Traduction: une liste (non vide) de Users séparés par des virgules.

La définition formelle d’un User est trop compliquée pour être détaillée ici mais quelques points sont à noter:

  • Un utilisateur est représenté par son nom de compte user,
  • Un groupe est représenté par non nom préfixé d’un caractère pour-cent: %group,
  • Il est possible de retirer des droits en préfixant d’un point d’exclamation: !user ou !%group.

Pour la liste exhaustive des cas, chercher User ::= dans le manuel de sudo.

Hosts

Ce que j’ai appelé $HOSTS au début de cette page est formellement défini comme suit: Host_List ::= Host | Host ',' Host_List. Ici comme pour $USERS: une liste non vide de Host séparés par des virgules.

Là encore, la définition d’un Host couvre plus de cas que ce qui m’intéresse et que voici:

  • Un hostname tel que localhost par exemple,
  • Une adresse IP,
  • Comme pour User, un point d’exclamation retire les droits.

Pour la liste exhaustive, chercher Host ::= dans le manuel de sudo.

Run as

Cette partie est optionnelle (ne pas mettre de parenthèses vide) et vaut simplement (root:root) par défaut soit utilisateur root, groupe root. Il est très fréquent de voir (ALL:ALL) à la place soit aucune limitation sur l’utilisateur et le groupe accessible via les options -u et -g de la commande sudo.

Dans le cas d’un $RUN_AS non vide, il y a plusieurs formes possibles:

  • (user): sudo ne sera accepté qu’avec -u user mais pas de -g,
  • (:group): sudo ne sera accepté qu’avec -g group mais pas de -u,
  • (user:group): sudo ne sera accepté qu’avec -u user et -g group.

Comme pour Users et Hosts, il s’agit d’une liste. La syntaxe suivante est donc valide: (user0,:group1,user2:group2). Il sera alors possible d’appeler sudo avec -u user0, -g group1 ou -u user2 -g group2 respectivement.

Options

Il existe pléthore d’options. Cependant, la seule que j’ai déjà utilisée et que j’aborderai donc est NOPASSWD:. Comme expliqué précédemment et sans surprise aucune, cette option fait en sorte qu’aucun mot de passe ne soit demandé à l’usage de sudo.

La liste des options est trouvable en cherchant Tag_Spec ::= dans le manuel de sudo.

Commands

La dernière partie, $COMMANDS consiste en une liste de Commands là encore séparées par des virgules.

  • La forme la plus simple d’une Command est le chemin absolu d’un exécutable: user ALL=/usr/bin/foo.
  • Renseigner un dossier avec le / final donne accès à l’intégralité des exécutables contenus dans ce dossier (mais pas au-delà, ce n’est pas récursif): %group ALL=/usr/bin/,
  • Il est possible d’ajouter les arguments autorisés pour un exécutable donné ou "" pour interdire toute option: user ALL=/foo/bar -h,/baz "",
  • Le mot-clé sudoedit suivi du chemin absolu d’un fichier indique qu’il est possible d’éditer ledit fichier, plus à ce propos par la suite: sudoedit /etc/hosts.

Notes

Ordre d’évaluation

Il est possible que, pour une situation donnée, plusieurs règles s’appliquent. Par exemple, un appelle à sudo peut être couvert pour l’utilisateur mais aussi pour un groupe dont l’utilisateur fait partie. Dans ce cas, la dernière règle valide s’applique.

L’ordre des lignes mais aussi le nom des fichiers dans /etc/sudoers.d a donc son importance.

Éditeurs

Il est fortement déconseillé d’autoriser un éditeur de texte à être lancé via sudo. Au lieu de ça, sudoedit file lancera l’édition du fichier file avec l’éditeur de texte par défaut ($EDITOR).

Autoriser un éditeur à ouvrir tous les fichiers avec les pleins pouvoir est tout de même bien plus risqué que d’autoriser n’importe quel éditeur à ouvrir un ensemble réduit de fichiers.

Sources

La miniature pour cet page est le Logo de sudo sous licence CCBY 4.0 distribué ici.