Einführung in Polkit: Navigieren in Autorisierungs-Frameworks unter Linux
Polkit ist ein Autorisierungs-Framework, das auf jeder modernen Linux-Distribution installiert ist: Es bietet APIs, die es privilegierten Anwendungen ermöglichen, Dienste für unprivilegierte Subjekte verfügbar zu machen. Die Kommunikation mit Polkit erfolgt über den D-Bus, ein IPC-System (Interprocess Communication). Um zu verstehen, wie Ersteres funktioniert, müssen wir zunächst verstehen, wie Letzteres implementiert wird.
In diesem Tutorial sprechen wir über Polkit; Wir sehen, wie es funktioniert und wie man die damit verbundenen Dienstprogramme unter Linux verwendet.
In diesem Tutorial lernen Sie:
- Welche Rolle spielen Polkit und D-Bus auf modernen Linux-Distributionen?
- So funktioniert Polkit
- So verwenden Sie die Dienstprogramme pkaction, pkcheck und pkexec
Polkit und D-Bus
Bevor wir anfangen, über Polkit zu sprechen und zu sehen, welche Rolle es in modernen Linux-basierten Betriebssystemen spielt, müssen wir verstehen, wie D-Bus funktioniert. D-Bus ist ein Message-Bus-System, das zur Kommunikation zwischen Prozessen verwendet wird. Einige Dienste registrieren sich auf dem Bus und stellen Informationen und Funktionalitäten als Eigenschaften, Signale und Methoden zur Verfügung. Jede Benutzersitzung erhält einen Sitzungsbus. Dienste, die darauf registriert sind, werden mit den Benutzerrechten ausgeführt. Systemweite Dienste, die möglicherweise als root laufen, registrieren sich stattdessen auf dem Systembus: Sie bieten Funktionen, die Administratorrechte erfordern, wie z.B. das Einbinden des Dateisystems. Dienstprogramme wie d-feet (GTK) oder QDBusViewer (QT) ermöglichen es uns, Dienste zu visualisieren, die in bestehenden Bussen registriert sind.
Beide Dienstprogramme zeigen in der linken Spalte Dienste, die auf einem Bus registriert sind, an (z. B. org.freedesktop.Accounts), und in der rechten Spalte den Pfad der Objekte, mit denen sie geliefert werden (z. B. /org/freedesktop/Accounts). Jedes Objekt stellt eine oder mehrere Schnittstellen bereit, die als Namespaces für Methoden, Signale und Eigenschaften fungieren.
In den Screenshots sehen Sie, dass der Dienst org.freedesktop.Accounts auf dem Systembus registriert ist: Er wird mit dem Objekt /org/freedesktop/Accounts geliefert, das die Schnittstelle org.freedesktop.Accounts bereitstellt. Die Schnittstelle enthält Methoden wie "CreateUser" und "DeleteUser". Das Erstellen und Löschen von Benutzern sind Aktionen, die Root-Rechte erfordern, daher muss es eine Möglichkeit für unprivilegierte Subjekte geben, die sie ausführen möchten, um Berechtigung zu bitten. Hier kommt Polkit ins Spiel.
So funktioniert Polkit
Polkit ist auf dem D-Bus-"System"-Bus mit dem Namen org.freedesktop.PolicyKit1 registriert. Der Dienst läuft nicht als root, sondern mit den Rechten des polkitd-Benutzers und der polkitd-Gruppe (siehe /usr/lib/systemd/system/polkit.service). Polkit muss nicht als root ausgeführt werden, da es selbst keine privilegierten Aktionen ausführt: Es prüft lediglich, ob ein Subjekt berechtigt ist, auf einen Dienst oder Mechanismus zuzugreifen, in der Polkit-Terminologie.
Um den Zugriff auf einen Dienst zu autorisieren, kann Polkit manchmal eine Person auffordern, sich als sie selbst oder als Administrator zu authentifizieren. Möglich wird dies durch den Einsatz eines Polkit-Agenten. Polkit wird mit einem Basismittel namens pkttyagent geliefert. Alle wichtigen Desktop-Umgebungen bieten jedoch eine eigene Agent-Implementierung. GNOME wird zum Beispiel mit dem Paket "polkit-gnome" geliefert, während das KDE "polkit-kde" usw. enthält. Der Agent wird automatisch mit der Benutzersitzung gestartet und mit den Benutzerrechten ausgeführt.
Das folgende Diagramm, das von der freedesktop-Seite polkit übernommen wurde, fasst zusammen, wie polkit funktioniert:
Wie entscheidet Polkit, ob ein Betroffener berechtigt ist, auf einen bestimmten Dienst zuzugreifen, und ob eine Authentifizierung erforderlich ist? Wie Sie im obigen Diagramm sehen können, konsultiert es im Wesentlichen zwei Dinge: Richtlinien und Regeln. Werfen wir einen Blick auf sie.
Polkit-Aktionen
Polkit-"Aktionen" werden in XML-Dateien mit der Erweiterung ".policy" im Verzeichnis /usr/share/polkit-1/actions definiert. Wir haben bereits den Dienst org.freedesktop.Accounts erwähnt. Aktionen, die damit in Verbindung stehen, werden in der Datei /usr/share/polkit-1/actions/org.freedesktop.accounts.policy definiert. Hier nehmen wir die Definition von einem als Beispiel auf:
<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>
Eine Aktion wird innerhalb von "action"-Tags definiert und über das Attribut "id" identifiziert. Die ID wird verwendet, um auf die Aktion aus dem Code oder aus benutzerdefinierten Polkit-Regeln zu verweisen (siehe unten). Der Dienst org.freedesktop.Accounts verweist beispielsweise auf die Aktion org.freedesktop.accounts.change-own-user-data, wenn wir eine Anfrage zum Ändern von Details unseres eigenen Benutzers stellen, entweder über das Einstellungsfeld unserer bevorzugten Desktop-Umgebung oder durch direktes Tätigen eines dbus-Aufrufs mit der dbus-send-Anwendung.
Mit dem Tag "description" geben wir eine kurze Beschreibung der Aktion; Mit dem Tag "message" definieren wir stattdessen die Nachricht, die einem Subjekt angezeigt wird, wenn es zur Authentifizierung aufgefordert wird.
Das Standardverhalten der Aktion wird in den "default"-Tags mit den Tags "allow_any", "allow_inactive" und "allow_active" definiert. Wofür werden sie verwendet? Polkit ist in der Lage, zwischen aktiven und inaktiven Clients zu unterscheiden und sein Verhalten entsprechend anzupassen. Die Tags "allow_active" und "allow_inactive" werden für aktive und inaktive Clients auf lokalen Konsolen oder grafischen Displays verwendet, während das Tag "allow_any" in allen anderen Situationen relevant wird, z. B. bei SSH- oder VNC-Remote-Verbindungen. Die in diesen Tags zulässigen Inhalte sind:
- Nein: Der Benutzer ist für die Aktion nicht autorisiert
- Ja: Der Benutzer ist für die Aktion autorisiert, ohne dass eine Authentifizierung erforderlich ist
- auth_self: Der Benutzer muss sich als er selbst authentifizieren (mit seinem eigenen Passwort), um autorisiert zu werden
- auth_self_keep: wie auth_self, aber Passwort wird gespeichert
- auth_admin: Der Benutzer muss sich als root authentifizieren, um für die Aktion autorisiert zu werden
- auth_admin_keep: wie auth_admin, aber Passwort wird wiedererkannt
In der oben enthaltenen Aktionsdefinition wird in allen Fällen "Ja" verwendet. Aus diesem Grund können wir, obwohl das Ändern eines Benutzers eine Aktion ist, die Root-Rechte erfordert, beispielsweise unser Passwort über das Einstellungsfeld unserer bevorzugten Desktop-Umgebung ändern, ohne uns für die Rechteerweiterung authentifizieren zu müssen.
Ein Tag, der in diesem Beispiel nicht vorkommt, ist "annotate": Es wird verwendet, um zusätzliche Schlüssel-Wert-Paare für eine Aktion bereitzustellen. Die bekanntesten Anmerkungen sind:
- org.freedesktop.policykit.exec.path: Dies hängt mit der Verwendung des Dienstprogramms pkexec zusammen, siehe unten.
- org.freedesktop.policykit.implly: wird verwendet, um "Meta"-Aktionen zu definieren. Nimmt eine Zeichenfolge an, die eine durch Leerzeichen getrennte Liste von Aktions-IDs enthält. Wenn ein Benutzer für diese Aktion autorisiert ist, wird er auch für diese autorisiert sein.
- org.freedesktop.policykit.owner: nimmt eine durch Leerzeichen getrennte Liste von PolkitIdentity-Einträgen (z.B. "unix-user:1000") an, die angibt, wer abfragen kann, ob ein Client berechtigt ist, die Aktion auszuführen: Eine typische Verwendung ist für Daemons, die nicht als root laufen.
Polkit-Regeln
Zusätzlich zu impliziten Aktionen sucht Polkit nach Regeln, mit denen feinkörnigere Richtlinien definiert werden können. Regeln, die von Anbietern bereitgestellt werden, werden im Verzeichnis /usr/share/polkit-1/rules.d installiert: Sie dürfen nicht an Ort und Stelle geändert werden, da sie möglicherweise durch Systemaktualisierungen überschrieben werden können. Benutzerbereitgestellte Regeln befinden sich stattdessen unter /etc/polkit-1/rules.d. Regeln werden mit Javascript in Dateien mit der Erweiterung ".rules" geschrieben. Hier ist ein Beispiel für eine Regel, die von der GNOME-Desktop-Umgebung als /usr/share/polkit-1/rules.d/gnome-control-center.rules installiert wurde:
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;
}
});
Die addRule-Methode des polkit-Objekts wird verwendet, um eine Funktion hinzuzufügen, die aufgerufen wird, wenn auf eine bestimmte Aktion verwiesen wird. Die Methode akzeptiert eine Funktion als Argument. Diese Funktion erhält zwei Argumente: "action" und "subject". Es handelt sich um zwei Objekte, die die beteiligte Aktion bzw. das Subjekt, das die Anforderung ausgeführt hat, darstellen.
Die Regeln legen fest, dass, wenn die ID der Aktion, auf die über die id-Eigenschaft des Aktionsobjekts zugegriffen wird, eine von "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" und "org.gnome.controlcenter.datetime.configure" ist", befindet sich das Subjekt in einer lokalen und aktiven Sitzung und ist Teil der "wheel"-Unix-Gruppe (dies ist das Äquivalent zur sudo-Gruppe in Debian-basierten Systemen), dann wird es autorisiert, ohne dass eine Authentifizierung erforderlich ist. Dies ist auf den zurückgegebenen Wert zurückzuführen: polkit. Result.YES. Die Rückgabewerte entsprechen den Werten, die wir zuvor in Aktionsdefinitionen gesehen haben, und sind in einem Wörterbuch organisiert:
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
};
Um eine unter /usr/share/polkit-1/rules.d definierte Regel zu überschreiben, können wir unter /etc/polkit-1/rules.d eine Datei mit demselben Namen erstellen. Regeln in beiden Verzeichnissen werden in lexikalischer Reihenfolge verarbeitet, aber wenn zwei Regeldateien mit demselben Namen in beiden Verzeichnissen vorhanden sind, hat die Datei unter /etc/polkit-1/rules.d Vorrang.
Für das Objekt "polkit" sind neben addRule noch andere Methoden verfügbar. Eine weitere häufig verwendete ist addAdminRule. Die Methode hat die gleiche Signatur wie addRule, wird aber immer dann aufgerufen, wenn eine Authentifizierung als Administrator erforderlich ist. Sie wird verwendet, um anzugeben, welche Identitäten sich als Administrator authentifizieren können. In den meisten Fällen wird die Methode wie im folgenden Beispiel verwendet, um die Mitglieder der Gruppe "wheel" einzuschließen:
polkit.addAdminRule(function(action, subject) {
return ["unix-group:wheel"];
});
Polkit-Dienstprogramme
Drei Befehlszeilenprogramme sind in jeder Polkit-Installation enthalten: "pkaction", "pkcheck" und "pkexec", sehen wir uns kurz an, wofür sie verwendet werden können.
pkaction
Das Dienstprogramm pkaction kann verwendet werden, um detaillierte Informationen über eine registrierte Polkit-Aktion abzurufen. Wenn das Dienstprogramm ohne Argument oder Option aufgerufen wird, zeigt es alle registrierten Aktionen an:
pkactionHier ist ein Auszug dessen, was der Befehl bei einer Standardinstallation von Fedora Workstation zurückgibt:
[...]
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
[...]
Um detaillierte Informationen über Aktionen und nicht nur deren Namen zu erhalten, können wir das Dienstprogramm mit der Option --verbose aufrufen. Um uns auf eine bestimmte Aktion zu konzentrieren, übergeben wir stattdessen ihren Namen als Argument an --action-id. Hier ist ein Beispiel, das die Aktion org.freedesktop.login1.halt beinhaltet:
pkaction --verbose --action-id org.freedesktop.login1.haltHier ist die Ausgabe, die wir erhalten würden:
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 (Englisch)
Das Dienstprogramm pkcheck wird verwendet, um zu überprüfen, ob ein Prozess berechtigt ist, eine bestimmte Aktion auszuführen, die von einem Dienst auf dem System-dbus verfügbar gemacht wird. Dieses Dienstprogramm ist im Grunde eine Befehlszeilenmethode zum Aufrufen der CheckAuthorization-Methode, die von der Polkit D-Bus-Schnittstelle verfügbar gemacht wird. Ein Prozess kann durch seinen Systembusnamen oder durch die Übergabe von Details wie PID, Startzeit und uid identifiziert werden. Um die letztere Strategie zu verwenden, übergeben wir solche Details als Argumente an die Option --process. Die Aktion, mit der wir den Prozess testen möchten, wird stattdessen als Argument für --action-id angegeben.
Hier ist ein Beispiel. Angenommen, ich möchte überprüfen, ob die interaktive Shell, von der aus ich arbeite, berechtigt ist, das System herunterzufahren (z. B. durch Ausführen des Befehls "systemctl halt"), würde ich Folgendes ausführen:
pkcheck -u --process $$ --action-id org.freedesktop.login1.haltDie Variable $$ wird in die PID der aktuellen Shell erweitert, und die Option -u, die wir als Teil des Befehls verwendet haben, ermöglicht die Benutzerauthentifizierung über einen Polkit-Agenten. Sobald wir den Befehl ausführen, werden wir tatsächlich aufgefordert, uns zu authentifizieren, da die referenzierte Aktion "auth_admin_keep" für alle Arten von Benutzern/Sitzungen verwendet:
<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>
Nachdem ich mich erfolgreich als Administrator authentifiziert habe (mein Benutzer befindet sich in der wheel-Gruppe), gibt das Dienstprogramm pkcheck die folgende Ausgabe zurück:
polkit\56temporary_authorization_id=tmpauthz3
polkit\56retains_authorization_after_challenge=true
Da der Prozess autorisiert ist, lautet der Exit-Code des Dienstprogramms 0:
echo $?
0Wenn ein Prozess nicht autorisiert ist, gibt das Dienstprogramm 3 als Vorhandenstatus zurück. Genauere Exit-Codes finden Sie in der Manpage.
Im obigen Beispiel haben wir nur die PID des Prozesses angegeben, den wir testen möchten, aber um Race Conditions zu vermeiden (PIDs können recycelt werden), wird empfohlen, das Format "pid,start-time,uid" zu verwenden. Um beispielsweise die Startzeit eines Prozesses zu erhalten, können wir einen Blick auf die Spalte 22 der zugehörigen Datei unter dem Pseudo-Dateisystem /proc werfen. Um den Startzeitwert eines Prozesses mit PID 87325 zu erhalten, würden wir Folgendes ausführen:
cat /proc/87325/stat | cut -d ' ' -f 22Oder:
awk -F ' ' '{print $22}' /proc/87325/statpkexec
Das Dienstprogramm pkexec kann verwendet werden, um einem Benutzer zu erlauben, ein Programm als ein anderer Benutzer auszuführen, typischerweise als root. Das ist im Grunde auch das, was sudo tut: Der wichtigste, große Unterschied zwischen den beiden besteht darin, dass pkexec im Kontext der Polkit-Infrastruktur mit all ihren Vorteilen und Komplexitäten arbeitet. Um einen Befehl als root mit pkexec auszuführen, übergeben wir einfach das Programm als Argument an pkexec. Hier ist ein Beispiel, in dem wir versuchen, Fedora mit dem Befehl dnf update zu aktualisieren:
pkexec dnf updateWenn wir mit GNOME oder einer anderen grafischen Umgebung arbeiten, die eine eigene Version des Polkit-Agenten bereitstellt, werden wir aufgefordert, uns in einer grafischen Eingabeaufforderung zu authentifizieren; Wenn wir den Befehl von einem TTY aus ausführen, wird stattdessen eine textuelle Eingabeaufforderung angezeigt, da Polkit auf den pkttyagent-Agenten zurückgreift:
==== AUTHENTICATING FOR org.freedesktop.policykit.exec ====
Authentication is needed to run `/usr/bin/dnf update' as the super user
Authenticating as: doc
Password:
Sobald wir uns erfolgreich authentifiziert haben, sollte der Befehl ohne Probleme ausgeführt werden. Leider werden Sie in den neueren Versionen von Polkit höchstwahrscheinlich stattdessen über einen Fehler benachrichtigt:
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.
Dies ist auf einen bekannten Fehler zurückzuführen. Ein möglicher Workaround besteht darin, den textuellen Agenten explizit zu starten:
pkttyagent -p $(echo $$) | pkexec dnf updateWenn pkaction verwendet wird, verweist es standardmäßig auf die Aktion org.freedesktop.policykit.exec, die in der Datei /usr/share/polkit-1/actions/org.freedesktop.policykit.policy definiert ist. Wenn wir möchten, dass pkexec auf eine benutzerdefinierte Aktion verweist, verwenden wir die Annotation org.freedesktop.policykit.exec.path für diese Aktion und legen den Pfad des Programms, das wir ausführen möchten, als Inhalt des "annotate"-Tags fest. Dies ist, was Gparted zumindest auf Fedora in der Datei /usr/share/polkit-1/actions/org.gnome.gparted.policy tut:
<?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>
Beachten Sie die andere Anmerkung, die in der Aktion verwendet wird: org.freedesktop.policykit.exec.allow_gui. Dies ist notwendig, da bei der Verwendung von pkexec viele Umgebungsvariablen gelöscht werden, um aus Sicherheitsgründen eine minimale bekannte Umgebung zu erhalten. Dies macht es unmöglich, X11-Anwendungen auszuführen, da die Variablen DISPLAY und XAUTHORITY gelöscht werden. Durch die Verwendung der Anmerkung wird dieses Verhalten deaktiviert.
Abschließende Gedanken
In diesem Tutorial haben wir über Polkit und D-Bus gesprochen und gesehen, wie die beiden Technologien zusammenhängen. Polkit ist ein Autorisierungs-Framework, das eine API bereitstellt, mit der nicht privilegierte Subjekte auf privilegierte Dienste zugreifen können. In diesem Tutorial haben wir gesehen, wie Polkit funktioniert, wie Polkit-Aktionen und -Regeln definiert werden und wie die Dienstprogramme pkaction, pkcheck und pkexec verwendet werden.




