Die Container-Engine Podman ermöglicht bekanntlich das Ausführen von Rootless-Containern und verzichtet auf den Einsatz eines Daemons. Beide Eigenschaften sorgen für mehr Sicherheit und ermöglichen zudem das Ausführen von Benutzersitzungen innerhalb eines Containers. Wir schauen uns hierfür das neue Podman-Feature podmansh an. Es erlaubt, Podman als Login-Shell für einen Benutzer zu verwenden.
Können Benutzer sich auf einem System interaktiv anmelden, beispielsweise mit der Secure Shell (SSH), ist es nicht nur notwendig, die Benutzersitzung möglichst gut abzusichern. Verantwortliche müssen auch festlegen, auf welche Daten ein User Zugriff erhalten darf und welche Informationen vor den Augen des Anwenders verborgen bleiben. Um diesen Zugriff zu regeln, kommt auf Linux-Systemen ein Modell namens Discretionary Access Control (DAC) zum Einsatz. Hierbei wird anhand der Benutzer-ID (POSIX UID) und der Gruppen-ID (POSIX-GID) entschieden, auf welche Ressourcen ein User Zugriff erhält.
Einfachere Regeln dank Container
Das Kernel-basierte SELinux führt mithilfe der sogenannten Mandatory Access Control (MAC) einen zusätzlichen Schutz ein, um das DAC-basierte Modell um einen Layer zu erweitern, auf dessen Basis dann eine Entscheidung darüber getroffen wird, ob ein Benutzer Zugriff auf eine bestimmte Ressource enthält oder nicht. Allerdings ist das Schreiben eines solchen SELinux-Regelwerks recht komplex und fehleranfällig und stellt gerade Administratoren, die wenig Erfahrung mit SELinux haben, oftmals vor eine gewaltige Aufgabe.
Nun hat sich in den vergangenen Jahren der Einsatz von Containern immer mehr durchgesetzt und die meisten Admins verfügen über reichlich Erfahrung im Umgang damit. Da Container als Prozesse auf einem Host-System ablaufen, ist hier auch wieder der Einsatz von SELinux möglich, um den Zugriff der Container auf bestimmte Systemressourcen abzusichern.
Können Benutzer sich auf einem System interaktiv anmelden, beispielsweise mit der Secure Shell (SSH), ist es nicht nur notwendig, die Benutzersitzung möglichst gut abzusichern. Verantwortliche müssen auch festlegen, auf welche Daten ein User Zugriff erhalten darf und welche Informationen vor den Augen des Anwenders verborgen bleiben. Um diesen Zugriff zu regeln, kommt auf Linux-Systemen ein Modell namens Discretionary Access Control (DAC) zum Einsatz. Hierbei wird anhand der Benutzer-ID (POSIX UID) und der Gruppen-ID (POSIX-GID) entschieden, auf welche Ressourcen ein User Zugriff erhält.
Einfachere Regeln dank Container
Das Kernel-basierte SELinux führt mithilfe der sogenannten Mandatory Access Control (MAC) einen zusätzlichen Schutz ein, um das DAC-basierte Modell um einen Layer zu erweitern, auf dessen Basis dann eine Entscheidung darüber getroffen wird, ob ein Benutzer Zugriff auf eine bestimmte Ressource enthält oder nicht. Allerdings ist das Schreiben eines solchen SELinux-Regelwerks recht komplex und fehleranfällig und stellt gerade Administratoren, die wenig Erfahrung mit SELinux haben, oftmals vor eine gewaltige Aufgabe.
Nun hat sich in den vergangenen Jahren der Einsatz von Containern immer mehr durchgesetzt und die meisten Admins verfügen über reichlich Erfahrung im Umgang damit. Da Container als Prozesse auf einem Host-System ablaufen, ist hier auch wieder der Einsatz von SELinux möglich, um den Zugriff der Container auf bestimmte Systemressourcen abzusichern.
Da es in diesem Fall jedoch um Prozesse und nicht um Benutzersitzungen geht, reichen einfache SELinux-Type-Enforcement-Regeln aus, um den gewünschten Zugriff der Container-Prozesse abzusichern. Hierfür existieren bereits fertige SELinux-Regelwerke. Starten Sie eine User-Session innerhalb eines Containers, kommen neben SELinux natürlich auch alle weiteren Sicherheitsmechanismen für eine Container-Umgebung zum Einsatz. Hierzu zählen neben dem erwähnten SELinux auch der Einsatz von Kernel Capabilities [1] und User Namespaces [2].
Seit der Podman-Version 4.6 bietet die Container-Engine ein neues Feature an, um Sitzungen direkt innerhalb eines Containers zu starten: podmansh [3]. Die Grundlage hierfür bildet die Tatsache, dass systemd seit geraumer Zeit schon in der Lage ist, Container zu starten und zu verwalten. In der Vergangenheit konnten Sie mit dem folgenden Kommando sehr leicht eine systemd-Unit-Datei von einem beliebigen Container erzeugen:
# podman generate systemd<container>
Diese Funktion ist allerdings mittlerweile veraltet und es empfiehlt sich, stattdessen mit Quadlet-Dateien zu arbeiten. Das Quadlet-Tool [4] startete zuerst als eigenständiges Projekt, ist mittlerweile allerdings in die podman-Container-Engine integriert. Die Idee hierbei ist, dass Sie ein einfaches Template in Form einer systemd-Unit-Datei verwenden, um daraus mithilfe eines systemd-Generators eine Unit-Datei zu erzeugen und somit einen Container als regulären systemd-Service starten und verwalten zu können. Der Vorteil bei dieser Variante liegt darin, dass die Komplexität, die der Betrieb von Containern mit sich bringen kann, durch einfache Key/Value-Anweisungen in einer Quadlet-Datei verborgen bleibt.
Benutzer-Sessions mit podmansh
Möchten Sie nun schließlich das podmansh-Feature verwenden, um eine Session direkt nach dem User-Login innerhalb eines Containers auszuführen, können Sie für den podmansh-Container eine Quadlet-Datei erzeugen. Die beispielhafte Konfiguration aus dem Listing-Kasten würde nach dem Anmelden eines Users, der als Login-Shell podmansh nutzt, eine neue systemd-Unit erzeugen, den gewünschten Container als systemd-Service starten und dann die eigentliche Benutzer-Session innerhalb des Containers ausführen.
Im Bild können Sie erkennen, wie der systemd-Generator aus der einfachen Quadlet-Datei aus dem Listing eine doch recht komplexe systemd-Unit für den Benutzer-Container erzeugt. Dies verdeutlicht, wie die Komplexität dieses Setups durch die Kombination aus Quadlet, systemd-Generator und podmansh verborgen bleibt.
Ein Ausschnitt der aus der Quadlet-Datei erzeugten systemd Unit.
Das Quadlet aus dem Listing sorgt nun also dafür, dass für Benutzer, die als Login-Shell podmansh verwenden, ein Container auf Basis des centos:stream9-Images erzeugt wird und innerhalb des Containers ein Volume-Mount für das Home-Verzeichnis des Benutzers stattfindet. Auf dem Host-System liegen die Daten dann innerhalb von "~/data/". Somit sind die Daten des Users persistent und stehen auch in neu erzeugten Containern für diesen wieder zur Verfügung. Möchten Sie diese nicht verwenden, entfernen Sie die Volume-Anweisung einfach aus dem Quadlet.
Listing: podmansh-Konfiguration
Mithilfe einer Quadlet-Datei erzeugt podman systemd-Container-Services (/etc/containers/ systemd/users/podmansh.container):
[Unit]
Description=The Podmansh container
After=local-fs.target
[Container]
Image=centos:stream9
ContainerName=podmansh
RemapUsers=keep-id
RunInit=yes
Volume=%h/data:%h:Z
Exec=sleep infinity
[Service]
ExecStartPre=/usr/bin/mkdir -p %h/data
[Install]
RequiredBy=default.target
Auf der Hilfeseite zu Quadlet (man 5 quadlet) finden Sie genaue Informationen darüber, welche Anweisungen Sie innerhalb einer Quadlet-Datei verwenden können und welche Auswirkungen diese auf den daraus erzeugten Container haben. Das folgende Kommando zeigt, wie Sie einen neuen Benutzer "confinedu" anlegen und diesem podmansh als Login-Shell zuweisen:
# useradd -s /usr/bin/podmanshconfinedu
Melden Sie sich dann mithilfe von SSH auf dem System als Benutzer confinedu an, sehen Sie, dass die Umgebung des Users auf dem CentOS-Stream-Container-Image basiert und der Benutzer über Schreibzugriff auf sein Home-Verzeichnis verfügt:
# ssh confinedu@`hostname`
confinedu@fedora.tuxgeek.de'spassword:
Last login: Mon Nov 4 15:30:56 2024 from 192.168.0.91
# grep "^NAME" /etc/os-release
NAME="CentOS Stream"
# cd ~
# pwd
/home/confinedu
# echo "Hello World..." > hello.txt
# cat hello.txt
Hello World...
Auf dem Host-System läuft hingegen ein Fedora Linux und im Home-Verzeichnis des Benutzers sehen Sie im Unterverzeichnis "~/data" die innerhalb des Containers erzeugte Datei "hello.txt":
# grep "^NAME" /etc/os-release
NAME="Fedora Linux"
# sudo su -
# ls /home/confinedu/data/hello.txt
/home/confinedu/data/hello.txt
# cat /home/confinedu/data/hello.txt
Hello World...
Unterschiedliche Umgebungen
Möchten Sie einen Container in Abhängigkeit des Benutzers, der sich an dem System anmeldet, individuell konfigurieren, ist auch dies kein Problem. Hierzu erzeugen Sie im Ordner "/etc/containers/systemd/users/" einfach ein Unterverzeichnis, dessen Name identisch mit der UID des Benutzers ist, für den Sie einen individuellen Container erzeugen möchten. Die Quadlet-Datei für den Container legen Sie dann in diesem Unterverzeichnis ab. Haben Sie also beispielsweise einen Benutzer mit der UID 5000 und möchten eine Quadlet-Datei nur für diesen Benutzer erzeugen, lautet der Pfad zu dieser Datei "/etc/containers/systemd/users/5000/podmansh.container".
Fazit
Mit podmansh steht ein neues Podman-Feature zur Verfügung, mit dem Sie sehr leicht das Sicherheitslevel auf einem Linux-System erhöhen, indem Sie sämtliche Benutzer-Sessions innerhalb eigener Container starten. Hierdurch profitieren Sie automatisch von sämtlichen Sicherheitsfeatures, die die Podman Container-Engine mit sich bringt. Und dank des Einsatzes von Containern fällt die ansonsten umständliche SELinux-Konfiguration weit weniger komplex aus.