Podman: Linux-Container einfach gemacht, Teil 2

Seite 4: SECCOMP: Effektiv und komplex

Inhaltsverzeichnis

SECCOMP ist ein weiterer Sicherheitsmechanismus des Linux-Kerns, um festzulegen, welche Systemaufrufe ein Prozess verwenden darf. SECCOMP ist ebenso mächtig und effektiv wie komplex, da es in vielen Fällen nicht trivial und schon gar nicht offensichtlich ist, welche Systemaufrufe ein bestimmter Container und dessen Anwendung benötigt. Der Filtermechanismus von SECCOMP ist feingranular und erlaubt es, Systemaufrufe nach Namen beziehungsweise nach Nummern zu blockieren, nach bestimmten Argumenten, der Prozessorarchitektur und weiteren Eigenschaften. Viele Projekte wie Firefox, Chromium und OpenSSH greifen direkt auf SECCOMP zurück, um sich vor Angriffen zu schützen beziehungsweise um den potenziellen Schaden eines Angriffs einzudämmen.

Die meisten Container-Tools wie Docker und Podman, verwenden ein Whitelist-Profil, das festlegt, welche Systemaufrufe aufgerufen werden dürfen. Alle nicht genannten Aufrufe sind damit verboten. Dieses Standardprofil entspringt der Feder von Jessie Frazelle, einer Maintainerin des Docker-Projekts, und ist einer Herkules-Aufgabe gleichzusetzen – schließlich sollen möglichst alle Programme innerhalb eines Containers lauffähig bleiben und doch so viele Systemaufrufe wie möglich blockiert werden.

Bei Bedarf können Anwender ein eigenes SECCOMP-Profil im JSON-Format erstellen. Das folgende Beispiel erlaubt alle Systemaufrufe außer mkdir(2), sodass man keine neuen Verzeichnisse mehr anlegen kann.

$ cat seccomp.json
{
"defaultAction": "SCMP_ACT_ALLOW",
"architectures": [
"SCMP_ARCH_X86_64"
],
"syscalls": [
{
"names": [
"mkdir"
],
"action": "SCMP_ACT_ERRNO"
}
]
}
$ podman run --security-opt seccomp=seccomp.json alpine mkdir /neuesVerzeichnis
mkdir: can't create directory '/neuesVerzeichnis': Operation not permitted

Das obige Beispiel soll selbstverständlich lediglich SECCOMP demonstrieren. Aus Sicherheitsgründen sollte man stets Whitelist-Profile verwenden, die genau festlegen, welche Systemaufrufe erlaubt sind. Damit bleibt das Profil portabel, da die Anzahl der Systemaufrufe mit nahezu jeder neuen Version von Linux wächst. Momentan ist die Erstellung eines solchen Profils mit viel Handarbeit verbunden und damit fehleranfällig und für viele Anwender nicht umsetzbar.

Dessen sind sich die Podman-Entwickler durchaus bewusst und beteiligen sich deshalb am Google Summer of Code 2019. Sie arbeiten zusammen mit Studenten an einer Funktion, die dafür sorgen soll, dass Podman die Systemaufrufe innerhalb eines Containers mitliest, um anschließend ein passendes Profil zu generieren. Damit können Benutzer komfortabel auf Anwendungen spezialisierte SECCOMP-Profile generieren, um die Container noch weiter abzuriegeln.

Das Linux Security Module (LSM) ist ein Framework des Linux-Kerns, um verschiedene Sicherheitsmodelle zu unterstützen. Im Kontext von Containern spielen SELinux und AppArmor eine entscheidende Rolle. Abhängig von der Linux-Distribution wird in der Regel entweder SELinux (zum Beispiel auf Fedora) oder AppArmor (zum Beispiel auf Ubuntu) eingesetzt, um die Zwiebelschale an Sicherheitsmechanismen noch weiter zu vergrößern. In beiden Fällen handelt es sich um Zugriffskontrollen, die genau festlegen können, welcher Prozess mit welchen Rechten auf bestimmte Ressourcen, zum Beispiel auf ein Verzeichnis oder eine Datei, zugreifen kann.

Eine genaue Beschreibung von SELinux und AppArmor und wie sie im Kontext von Containern Verwendung finden, werden hier nur der Vollständigkeit halber erwähnt. Beide Module sind jedoch hinreichend komplex, um deren Konfiguration den jeweiligen Spezialisten der Linux-Distributionen zu überlassen. Podman unterstützt wie Docker sowohl AppArmor als auch SELinux.

Wie in (LB2616181:Teil 1 der Artikelserie) beschrieben, ist Podman besonders bekannt für die Rootless-Unterstützung, also das Ausführen von Containern, ohne Root-Rechte zu besitzen. Ein klassischer Anwendungsfall dafür ist ein Universitätslabor, in welchem Studenten aus Sicherheitsgründen keine Root-Rechte besitzen dürfen. Mit Podman können Studenten dennoch Container ausführen und ihrer Arbeit nachgehen. Das klingt zunächst nach einer Kleinigkeit, doch hinderte es für lange Zeit die Verbreitung und Anwendung von Containern in vielen Umgebungen.

User Namespaces spielen hierbei eine zentrale Rolle – da der Artikel sie bereits genauer beleuchtet hat, kann man Rootless-Podman nun am Beispiel von Fedora genauer betrachten. Wie ist das System genau konfiguriert und welche Teile spielen zusammen, um Rootless-Podman möglichst benutzerfreundlich zu halten?

Zeitgemäße Linux-Distributionen, wie das vor kurzem veröffentlichte Fedora 30, kommen mit einer Version von shadow-utils, die auf die /etc/subuid und /etc/subgid zurückgreift. Die beiden Dateien werden verwendet um herauszufinden, welche UIDs und GIDs Benutzern in einem User Namespace zur Verfügung stehen.

$ cat /etc/subuid /etc/subgid
valentin:100000:65536
valentin:100000:65536

Das Programm useradd(8) fügt für jeden neuen Benutzer einen Eintrag in die beiden Dateien ein. Sofern nicht auf der Kommandozeile weiter angegeben, verwendet Podman /etc/subuid und /etc/subgid für die Zuordnung von UIDs und GIDs von Host und Container User Namespace.

$ id -u
1000
$ podman run alpine cat /proc/self/uid_map
0 1000 1
1 100000 65536

Das obige Beispiel zeigt, dass der Host Benutzer mit der UID 1000 die UID 0 innerhalb des Containers hat. Die folgenden 65536 werden beginnend ab Host UID 100000 der Container UID 1 ff. entsprechend zugewiesen.

Ein wichtiger Punkt beim Einsatz von Rootless-Podman fand bisher noch keine Erwähnung: die Berechtigungen des Dateisystems. Alle Dateien und Verzeichnisse von Root eines Container-Images müssen schließlich dem Root innerhalb des User Namespace gehören. Andernfalls gelten sie als zu "nobody" gehörig und Anwender hätten keinerlei Zugriff. Die github.com/containers/storage-Bibliothek, auf der Podman aufbaut, unterstützt momentan zwei rootless-storage-Treiber, vfs und Overlay. Im Vergleich zu Overlay ist vfs langsam und speicherhungrig, da das gesamte RootFS für das Ausführen des Containers kopiert und die Berechtigungen angepasst werden müssen. Overlay ist wesentlich performanter, setzt für rootless aber voraus, dass das Programm fuse-overlayfs installiert ist.