SELinux¶
Diese Seite erklärt, wie SELinux die Container auf unseren Hosts voneinander trennt und welche Option jedes Volume deshalb bekommt.
Container voneinander trennen¶
Alle Container eines Hosts teilen sich dessen Betriebssystem.
Wird eine App kompromittiert, etwa über eine Sicherheitslücke, trennen nur die normalen Dateirechte den Container von den Daten anderer Container und von den Dateien des Hosts.
Viele Container laufen intern aber als root oder unter denselben Benutzernummern; die Dateirechte allein trennen sie deshalb kaum.
SELinux trennt zusätzlich über Labels: Jeder Container bekommt beim Start ein eigenes Label, das zufällig gewählte Kategorien enthält. Dateien, die zu diesem Container gehören, tragen dieselben Kategorien. SELinux lässt einen Container nur an Dateien, deren Label zu seinem passt, unabhängig davon, unter welchem Benutzer er läuft.
SELinux bleibt eingeschaltet. Wird ein Container kompromittiert, kommt man von dort aus nicht an die Daten anderer Container und nicht an die Dateien des Hosts. SELinux gehört zu Rocky Linux, und Podman setzt die Labels für die Container selbst; der Aufwand für uns beschränkt sich auf die Optionen der Volumes.
SELinux auf unseren Hosts¶
SELinux ist auf allen Hosts eingeschaltet, im Modus enforcing.
Im Alltag merkt man davon meist nichts. Alle Anwendungen laufen in Containern, und Podman setzt die nötigen Labels für die Container selbst. Unsere einzige Aufgabe ist, bei jedem Volume und jedem Bind-Mount die passende Option anzugeben (siehe Volume-Optionen).
Volume-Optionen¶
Welches Label die Dateien in einem Volume bekommen, bestimmt die Option hinter dem Pfad, zum Beispiel :Z in "/var/lib/postgresql/data:rw,Z,U".
Podman setzt das Label beim Start des Containers neu; das heißt Relabeln.
| Option | Bedeutung | Wann | Beispiel im Repo |
|---|---|---|---|
Z |
privates Label: nur dieser eine Container kommt an die Dateien | Standardfall, für alle Daten, die nur ein Container braucht | hedgedoc-postgres-data in syslet/werner/stack-hedgedoc.cue; der Bind-Mount /srv/kiosk in syslet/containerhost/stack-kioskserver.cue |
z |
geteiltes Label: alle Container, die das Volume einbinden, kommen an die Dateien | wenn mehrere Container dasselbe Volume brauchen | redirect-updater-data in syslet/werner/stack-redirect.cue, das ein Container schreibt und ein anderer ausliefert |
U |
passt zusätzlich den Besitzer der Dateien an den Benutzer im Container an | wenn die App nicht als root läuft und in das Volume schreiben muss |
Z,U und z,U bei den Postgres-Datenbanken in stack-hedgedoc.cue |
| keine | kein Relabeln | nur in den Ausnahmen unten | /mnt/backup in syslet/containerhost/stack-resticserver.cue |
Alles, was gesichert wird, braucht z¶
Der Backup-Container bindet jedes Volume ein, das im backup-Block eines Stacks steht (siehe Addons), und zwar mit z.
Diese Volumes werden also immer von mindestens zwei Containern genutzt und müssen auch in der App z haben, zum Beispiel die Uploads (hedgedoc-server-uploads) und die Datenbank-Dumps (hedgedoc-postgres-backups) von HedgeDoc.
Was ohne Option passiert¶
Ohne Option relabelt Podman nichts; was dann passiert, hängt davon ab, was eingebunden wird:
- Bind-Mount: Der Ordner behält das Label, das er auf dem Host hat. Der Container darf in aller Regel nicht darauf zugreifen und bekommt „Permission denied“, obwohl die Dateirechte stimmen.
- Benanntes Volume: Podman legt neue Volumes von vornherein mit einem geteilten Label an.
Ohne Option verhält sich das Volume deshalb wie mit
z: Es funktioniert, aber jeder Container, der es einbindet, kommt an die Daten.
Darum geben wir die Option immer an, auch wo es ohne funktionieren würde: Mit Z ist ein Volume tatsächlich auf seinen Container beschränkt, und wer die Stack-Datei liest, sieht, ob ein Volume geteilt sein soll.
Falsches Z auf einem geteilten Volume¶
Binden zwei Container dasselbe Volume ein und einer davon mit Z, bekommt das Volume beim Start dieses Containers dessen privates Label.
Der andere Container kommt danach nicht mehr an die Dateien.
Welcher Container ausgesperrt ist, hängt davon ab, welcher zuletzt gestartet wurde; der Fehler tritt deshalb oft erst nach einem Neustart auf.
Ausnahmen: nie relabeln¶
Diese Pfade nie mit Z oder z einbinden
Systempfade des Hosts.
Der node-exporter in syslet/werner/stack-nodeexporter.cue liest das ganze Dateisystem des Hosts (/), um Messwerte zu sammeln.
Mit Z oder z würde Podman jede Datei des Hosts umlabeln, und andere Dienste auf dem Host würden nicht mehr funktionieren.
Der node-exporter bindet / deshalb ohne Option und nur lesend ein und läuft mit --privileged, wodurch SELinux ihn nicht von den Dateien des Hosts trennt.
Ähnlich der Podman-Exporter in derselben Datei: Er bindet den Podman-Socket ohne Option ein und bekommt stattdessen ein eigenes Label (label=type:container_runtime_t), mit dem er darauf zugreifen darf.
NFS-Mounts.
/mnt/backup auf containerhost ist der Backup-Ordner des NAS, eingebunden per NFS.
Unser NFS-Mount speichert keine SELinux-Labels je Datei, und Podman überspringt das Relabeln dort ohne Meldung.
Z oder z hätten also keine Wirkung, würden in der Stack-Datei aber einen Schutz vortäuschen, den es nicht gibt.
Die Container in syslet/containerhost/stack-resticserver.cue binden ihn deshalb ohne Option ein.
Solche Ausnahmen sind selten und sollten in der Stack-Datei mit einem Kommentar begründet sein.
Wenn etwas nicht geht¶
Meldet ein Container „Permission denied“ auf einem Volume, ist meist die Option falsch oder fehlt. Behoben wird das in der Stack-Datei und mit apply, nicht von Hand auf dem Host und nie durch Abschalten von SELinux (siehe Was man von Hand darf).
Wie man den Fehler findet und behebt, steht in „Permission denied“ durch SELinux beheben.
Weiterlesen¶
- Podman: was Volumes und Bind-Mounts sind
- Grundsätze im Selfhosting
- Podman-Doku zu Volume-Optionen:
z,ZundUim Detail - Red Hat: Using SELinux