Introduction à Polkit : Navigation dans les frameworks d’autorisation sous Linux
Polkit est un cadre d’autorisation installé sur toutes les distributions Linux modernes : il fournit une API qui permet aux applications privilégiées d’exposer des services à des sujets non privilégiés. Les communications avec Polkit se font via D-Bus, qui est un système IPC (Interprocess Communication) ; Pour comprendre comment le premier fonctionne, nous devons d’abord comprendre comment le second est mis en œuvre.
Dans ce tutoriel, nous parlons de Polkit ; nous voyons comment cela fonctionne et comment utiliser les utilitaires qui l’accompagnent sous Linux.
Dans ce tutoriel, vous allez apprendre :
- Quel est le rôle de Polkit et D-Bus sur les distributions Linux modernes ?
- Comment fonctionne Polkit
- Comment utiliser les utilitaires pkaction, pkcheck et pkexec
Polkit et D-Bus
Avant de commencer à parler de Polkit, et de voir quel est son rôle dans les systèmes d’exploitation modernes basés sur Linux, nous devons comprendre comment fonctionne D-Bus. D-Bus est un système de bus de messages, utilisé pour permettre la communication entre les processus. Certains services s’enregistrent sur le bus et exposent des informations et des fonctionnalités sous forme de propriétés, de signaux et de méthodes. Chaque session utilisateur reçoit un bus de session ; Les services qui y sont enregistrés, s’exécutent avec les privilèges de l’utilisateur. Les services à l’échelle du système qui peuvent s’exécuter en tant que root s’enregistrent sur le bus système : ils offrent des fonctionnalités qui nécessitent des privilèges administratifs, tels que le montage du système de fichiers. Des utilitaires tels que d-feet (GTK) ou QDBusViewer (QT) nous permettent de visualiser les services enregistrés sur les bus existants.
Les deux utilitaires affichent les services enregistrés sur un bus dans la colonne de gauche (par exemple, org.freedesktop.Accounts) et le chemin d’accès des objets avec lesquels ils sont fournis, sur la droite (par exemple, /org/freedesktop/Accounts). Chaque objet fournit une ou plusieurs interfaces qui agissent comme des espaces de noms pour les méthodes, les signaux et les propriétés.
Dans les captures d’écran, vous pouvez voir que le service org.freedesktop.Accounts est enregistré sur le bus système : il est fourni avec l’objet /org/freedesktop/Accounts, qui fournit l’interface org.freedesktop.Accounts. L’interface comprend des méthodes telles que « CreateUser » et « DeleteUser ». La création et la suppression d’utilisateurs sont des actions qui nécessitent des privilèges root, il doit donc y avoir un moyen pour les sujets non privilégiés qui veulent les effectuer, de demander une autorisation. C’est là que Polkit entre en jeu.
Comment fonctionne Polkit
Polkit est enregistré sur le bus « system » D-Bus avec le nom org.freedesktop.PolicyKit1. Le service ne s’exécute pas en tant que root, mais avec les privilèges de l’utilisateur polkitd et du groupe polkitd (voir /usr/lib/systemd/system/polkit.service). Polkit n’a pas besoin de s’exécuter en tant que root, car il n’exécute pas lui-même des actions privilégiées : il vérifie simplement si un sujet est autorisé à accéder à un service, ou à un mécanisme, dans la terminologie Polkit.
Parfois, afin d’autoriser l’accès à un service, Polkit peut demander à un sujet de s’authentifier en tant qu’elle-même ou en tant qu’administrateur. Ce qui rend cela possible, c’est l’utilisation d’un agent polkit. Polkit est livré avec un agent de base, appelé pkttyagent ; Cependant, tous les principaux environnements de bureau fournissent leur propre implémentation d’agent. GNOME, par exemple, est livré avec le paquet « polkit-gnome », tandis que le KDE inclut « polkit-kde », etc. L’agent démarre automatiquement avec la session utilisateur et s’exécute avec les privilèges utilisateur.
Le schéma ci-dessous, tiré de la page polkit freedesktop, résume le fonctionnement de polkit :
Comment Polkit décide-t-il si un sujet est autorisé à accéder à un certain service et si une authentification est requise ? Comme vous pouvez le voir dans le schéma ci-dessus, il consulte essentiellement deux choses : les politiques et les règles. Jetons-y un coup d’œil.
Les actions de Polkit
Les « actions » Polkit sont définies dans des fichiers XML avec l’extension « .policy », dans le répertoire /usr/share/polkit-1/actions. Nous avons mentionné précédemment le service org.freedesktop.Accounts ; Les actions qui s’y rapportent sont définies dans le fichier /usr/share/polkit-1/actions/org.freedesktop.accounts.policy. Ici, nous incluons la définition de un à titre d’exemple :
<action id="org.freedesktop.accounts.change-own-user-data">
<description>Change your own user data</description>
<message>Authentication is required to change your own user data</message>
<defaults>
<allow_any>yes</allow_any>
<allow_inactive>yes</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
Une action est définie à l’intérieur de balises « action », et elle est identifiée via l’attribut « id ». L’ID est utilisé pour référencer l’action à partir du code ou des règles Polkit personnalisées (voir ci-dessous). Le service org.freedesktop.Accounts, par exemple, fait référence à l’action org.freedesktop.accounts.change-own-user-data lorsque nous émettons une demande de modification des détails de notre propre utilisateur, soit via le panneau des paramètres de notre environnement de bureau préféré, soit en émettant un appel dbus directement, avec l’application dbus-send.
Avec la balise « description », nous fournissons une brève description de l’action ; Avec la balise « message », en revanche, nous définissons le message qui s’affiche à un sujet lorsqu’il est invité à s’authentifier.
Le comportement par défaut de l’action est défini à l’intérieur des balises « default », à l’aide des balises « allow_any », « allow_inactive » et « allow_active ». À quoi servent-ils ? Polkit est capable de faire la distinction entre les clients actifs et inactifs, et d’ajuster son comportement en conséquence. Les balises « allow_active » et « allow_inactive » sont utilisées pour les clients actifs et inactifs sur les consoles locales ou les écrans graphiques, tandis que la balise « allow_any » devient pertinente dans toutes les autres situations, telles que les connexions à distance SSH ou VNC. Les contenus autorisés dans ces balises sont les suivants :
- Non : l’utilisateur n’est pas autorisé sur l’action
- Oui : l’utilisateur est autorisé sur l’action sans qu’il soit nécessaire de s’authentifier
- auth_self : l’utilisateur doit s’authentifier en tant que lui-même (avec son propre mot de passe) pour être autorisé
- auth_self_keep : identique à auth_self mais le mot de passe est réinitialisé
- auth_admin : l’utilisateur doit s’authentifier en tant que root pour être autorisé sur l’action
- auth_admin_keep : identique à auth_admin, mais le mot de passe est réinitialisé
Dans la définition de l’action ci-dessus, « oui » est utilisé dans tous les cas. C’est pour cette raison que, bien que la modification d’un utilisateur soit une action qui nécessite des privilèges root, nous pouvons, par exemple, changer notre mot de passe depuis le panneau de paramètres de notre environnement de bureau préféré sans avoir à nous authentifier pour l’élévation de privilèges.
Une balise qui n’apparaît pas dans cet exemple est « annotate » : elle est utilisée pour fournir des paires clé-valeur supplémentaires pour une action. Les annotations les plus connues sont :
- org.freedesktop.policykit.exec.path : ceci est lié à l’utilisation de l’utilitaire pkexec, voir ci-dessous.
- org.freedesktop.policykit.imply : utilisé pour définir les actions « méta ». Prend une chaîne contenant une liste d’ID d’action séparés par des espaces. Si un utilisateur est autorisé pour cette action, il sera également autorisé pour celles-ci.
- org.freedesktop.policykit.owner : prend une liste d’entrées PolkitIdentity séparées par des espaces (par exemple « unix-user :1000 ») qui spécifie qui peut demander si un client est autorisé à effectuer l’action : une utilisation typique est pour les démons qui ne s’exécutent pas en tant que root.
Règles du Polkit
En plus des actions implicites, Polkit recherche des règles, qui peuvent être utilisées pour définir des politiques plus précises. Les règles fournies par les fournisseurs sont installées dans le répertoire /usr/share/polkit-1/rules.d : elles ne doivent pas être modifiées sur place, car elles peuvent être potentiellement remplacées par les mises à jour du système. Les règles fournies par l’utilisateur, en revanche, se trouvent sous /etc/polkit-1/rules.d. Les règles sont écrites en Javascript, dans des fichiers avec l’extension « .rules ». Voici un exemple de règle installée par l’environnement de bureau GNOME sous la forme /usr/share/polkit-1/rules.d/gnome-control-center.rules :
polkit.addRule(function(action, subject) {
if ((action.id == "org.freedesktop.locale1.set-locale" ||
action.id == "org.freedesktop.locale1.set-keyboard" ||
action.id == "org.freedesktop.ModemManager1.Device.Control" ||
action.id == "org.freedesktop.hostname1.set-static-hostname" ||
action.id == "org.freedesktop.hostname1.set-hostname" ||
action.id == "org.gnome.controlcenter.datetime.configure") &&
subject.local &&
subject.active &&
subject.isInGroup ("wheel")) {
return polkit.Result.YES;
}
});
La méthode addRule de l’objet polkit est utilisée pour ajouter une fonction qui est appelée lorsqu’une action spécifique est référencée. La méthode accepte une fonction comme argument. Cette fonction reçoit deux arguments : « action » et « sujet ». Il s’agit de deux objets qui représentent respectivement l’action impliquée et le sujet qui a exécuté la demande.
Les règles établissent que, si l’ID de l’action, accessible via la propriété id de l’objet d’action, est l’un des suivants : « org.freedesktop.locale1.set-locale », « org.freedesktop.locale1.set-keyboard », « org.freedesktop.ModemManager1.Device.Control », « org.freedesktop.hostname1.set-static-hostname », « org.freedesktop.hostname1.set-hostname » et « org.gnome.controlcenter.datetime.configure« , le sujet est sur une session locale et active, et fait partie du groupe unix « wheel » (c’est l’équivalent du groupe sudo dans les systèmes basés sur Debian), alors il sera autorisé sans qu’il soit nécessaire de s’authentifier. Cela est dû à la valeur renvoyée : polkit. Les valeurs renvoyées sont équivalentes aux valeurs que nous avons vues précédemment dans les définitions d’actions, et sont organisées dans un dictionnaire :
polkit.Result = {
NO : "no",
YES : "yes",
AUTH_SELF : "auth_self",
AUTH_SELF_KEEP : "auth_self_keep",
AUTH_ADMIN : "auth_admin",
AUTH_ADMIN_KEEP : "auth_admin_keep",
NOT_HANDLED : null
};
Afin d’écraser une règle définie sous /usr/share/polkit-1/rules.d, nous pouvons créer un fichier portant le même nom sous /etc/polkit-1/rules.d. Les règles dans les deux répertoires sont traitées dans l’ordre lexical, mais si deux fichiers de règles portant le même nom existent dans les deux répertoires, celui sous /etc/polkit-1/rules.d prévaut.
Il existe d’autres méthodes disponibles sur l’objet « polkit », autres que addRule. Un autre modèle couramment utilisé est addAdminRule. La méthode a la même signature que addRule, mais est appelée chaque fois qu’une authentification en tant qu’administrateur est requise. Il est utilisé pour spécifier quelles identités peuvent s’authentifier en tant qu’administrateur. Dans la plupart des cas, la méthode est utilisée, comme dans l’exemple ci-dessous, pour inclure les membres du groupe « wheel » :
polkit.addAdminRule(function(action, subject) {
return ["unix-group:wheel"];
});
Utilitaires Polkit
Trois utilitaires en ligne de commande sont inclus dans toute installation de Polkit : « pkaction », « pkcheck » et « pkexec », voyons brièvement à quoi ils peuvent servir.
pkaction
L’utilitaire pkaction peut être utilisé pour récupérer des informations détaillées sur une action Polkit enregistrée. Lorsque l’utilitaire est appelé sans argument ni option, il affiche toutes les actions enregistrées :
pkactionVoici un extrait de ce que la commande renvoie sur une installation standard de Fedora Workstation :
[...]
org.freedesktop.login1.attach-device
org.freedesktop.login1.chvt
org.freedesktop.login1.flush-devices
org.freedesktop.login1.halt
org.freedesktop.login1.halt-ignore-inhibit
org.freedesktop.login1.halt-multiple-sessions
org.freedesktop.login1.hibernate
org.freedesktop.login1.hibernate-ignore-inhibit
org.freedesktop.login1.hibernate-multiple-sessions
org.freedesktop.login1.inhibit-block-idle
org.freedesktop.login1.inhibit-block-shutdown
org.freedesktop.login1.inhibit-block-sleep
org.freedesktop.login1.inhibit-delay-shutdown
org.freedesktop.login1.inhibit-delay-sleep
org.freedesktop.login1.inhibit-handle-hibernate-key
org.freedesktop.login1.inhibit-handle-lid-switch
org.freedesktop.login1.inhibit-handle-power-key
org.freedesktop.login1.inhibit-handle-reboot-key
org.freedesktop.login1.inhibit-handle-suspend-key
[...]
Pour obtenir des informations détaillées sur les actions, et pas seulement leurs noms, nous pouvons appeler l’utilitaire avec l’option --verbose. Pour se concentrer sur une action spécifique, nous passons son nom en argument à --action-id. Voici un exemple qui implique l’action org.freedesktop.login1.halt :
pkaction --verbose --action-id org.freedesktop.login1.haltVoici le résultat que nous obtiendrions :
org.freedesktop.login1.halt:
description: Halt the system
message: Authentication is required to halt the system.
vendor: The systemd Project
vendor_url: https://systemd.io
icon:
implicit any: auth_admin_keep
implicit inactive: auth_admin_keep
implicit active: auth_admin_keep
annotation: org.freedesktop.policykit.imply -> org.freedesktop.login1.set-wall-messagepkcheck
L’utilitaire pkcheck est utilisé pour vérifier si un processus est autorisé à effectuer une certaine action exposée par un service sur le système dbus. Cet utilitaire est essentiellement un moyen en ligne de commande d’invoquer la méthode CheckAuthorization exposée par l’interface D-Bus de polkit. Un processus peut être identifié par son nom de bus système ou en transmettant des détails tels que son PID, son heure de démarrage et son UID. Pour utiliser cette dernière stratégie, nous passons ces détails en tant qu’arguments à l’option --process. L’action contre laquelle nous voulons tester le processus, à la place, est spécifiée en argument de --action-id.
En voici un exemple. Supposons que je veuille vérifier si le shell interactif à partir duquel je travaille est autorisé à arrêter le système (en exécutant la commande « systemctl halt », par exemple), j’exécuterais :
pkcheck -u --process $$ --action-id org.freedesktop.login1.haltLa variable $$ se développe dans le PID du shell actuel, et l’option -u que nous avons utilisée dans le cadre de la commande permet l’authentification de l’utilisateur via un agent Polkit. Dès que nous exécutons la commande, nous sommes en effet invités à nous authentifier, puisque l’action référencée utilise « auth_admin_keep » pour tous les types d’utilisateurs/sessions :
<action id="org.freedesktop.login1.halt">
<description gettext-domain="systemd">Halt the system</description>
<message gettext-domain="systemd">Authentication is required to halt the system.</message>
<defaults>
<allow_any>auth_admin_keep</allow_any>
<allow_inactive>auth_admin_keep</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.set-wall-message</annotate>
</action>
Une fois que je me suis authentifié avec succès en tant qu’administrateur (mon utilisateur est dans le groupe wheel), l’utilitaire pkcheck renvoie le résultat suivant :
polkit\56temporary_authorization_id=tmpauthz3
polkit\56retains_authorization_after_challenge=true
Comme le processus est autorisé, le code de sortie de l’utilitaire est 0 :
echo $?
0Lorsqu’un processus n’est pas autorisé, l’utilitaire renvoie l’état 3 as exist. Pour des codes de sortie plus spécifiques, jetez un coup d’œil à la page de manuel.
Dans l’exemple ci-dessus, nous avons fourni uniquement le PID du processus que nous voulons tester, cependant, afin d’éviter les conditions de concurrence (les PID peuvent être recyclés), il est recommandé d’utiliser le format « pid,start-time,uid ». Pour obtenir l’heure de démarrage d’un processus, par exemple, nous pouvons jeter un coup d’œil à la colonne 22 du fichier associé sous le pseudo système de fichiers /proc. Pour obtenir la valeur start-time d’un processus avec le PID 87325, nous exécuterions :
cat /proc/87325/stat | cut -d ' ' -f 22Ou:
awk -F ' ' '{print $22}' /proc/87325/statpkexec
L’utilitaire pkexec peut être utilisé pour permettre à un utilisateur d’exécuter un programme en tant qu’un autre utilisateur, généralement en tant que root. C’est aussi fondamentalement ce que fait sudo : la principale, grande, différence entre les deux est que pkexec fonctionne dans le contexte de l’infrastructure Polkit, avec tous ses avantages et ses complexités. Pour exécuter une commande en tant que root avec pkexec, il suffit de passer le programme en argument à pkexec. Voici un exemple dans lequel nous essayons de mettre à jour Fedora à l’aide de la commande dnf update :
pkexec dnf updateSi nous fonctionnons sur GNOME ou un autre environnement graphique qui fournit sa propre version de l’agent polkit, nous serons invités à nous authentifier dans une invite graphique ; si nous exécutons la commande à partir d’un ATS, à la place, une invite textuelle apparaîtra, puisque Polkit reviendra à l’agent pkttyagent :
==== AUTHENTICATING FOR org.freedesktop.policykit.exec ====
Authentication is needed to run `/usr/bin/dnf update' as the super user
Authenticating as: doc
Password:
Une fois que nous nous sommes authentifiés avec succès, la commande devrait être exécutée sans problème. Malheureusement, dans les versions récentes de Polkit, il est fort probable que vous soyez informé d’une erreur à la place :
polkit-agent-helper-1: error response to PolicyKit daemon: GDBus.Error:org.freedesktop.PolicyKit1.Error.Failed: No session for cookie
==== AUTHENTICATION FAILED ====
Error executing command as another user: Not authorized
This incident has been reported.
Cela est dû à un bogue connu. Une solution de contournement possible consiste à lancer explicitement l’agent textuel :
pkttyagent -p $(echo $$) | pkexec dnf updatePar défaut, lorsque pkaction est utilisé, il fait référence à l’action org.freedesktop.policykit.exec, définie dans le fichier /usr/share/polkit-1/actions/org.freedesktop.policykit.policy. Si nous voulons que pkexec fasse référence à une action personnalisée, nous utilisons l’annotation org.freedesktop.policykit.exec.path sur ladite action, et définissons le chemin du programme que nous voulons exécuter comme contenu de la balise « annotate ». Voici ce que, du moins sur Fedora, Gparted fait dans le fichier /usr/share/polkit-1/actions/org.gnome.gparted.policy :
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
<policyconfig>
<vendor>The GParted Project</vendor>
<vendor_url>https://gparted.org</vendor_url>
<icon_name>gparted</icon_name>
<action id="org.gnome.gparted">
<description>Run GParted as root</description>
<message>Authentication is required to run the GParted Partition Editor as root</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/gparted</annotate>
<annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
</action>
</policyconfig>
Remarquez l’autre annotation utilisée dans l’action : org.freedesktop.policykit.exec.allow_gui. Ceci est nécessaire car lorsque pkexec est utilisé, il supprime beaucoup de variables d’environnement pour maintenir un environnement minimal connu, pour la sécurité. Cela rend impossible l’exécution des applications X11, puisque les variables DISPLAY et XAUTHORITY sont supprimées. L’utilisation de l’annotation désactive ce comportement.
Réflexions finales
Dans ce tutoriel, nous avons parlé de Polkit et de D-Bus, et nous avons vu comment les deux technologies sont liées. Polkit est un cadre d’autorisation qui fournit une API permettant aux sujets non privilégiés d’accéder à des services privilégiés. Dans ce tutoriel, nous avons vu comment fonctionne Polkit, comment les actions et les règles Polkit sont définies, et comment utiliser les utilitaires pkaction, pkcheck, pkexec.




