Podman Container & User Namespaces ¶
Grundprinzip ¶
Bei rootless Podman sind Container-UIDs und Host-UIDs nicht zwangsläufig identisch.
Entscheidend ist das User-Namespace-Mapping:
Container-Prozess
│
│ Container UID/GID
▼
User Namespace Mapping
│
│ Host UID/GID
▼
Host-Dateisystem
User= und UserNS= haben dabei unterschiedliche Aufgaben:
| Einstellung | Bedeutung |
|---|---|
| User= | Welcher User läuft im Container? |
| UserNS= | Wie werden Container-UIDs auf Host-UIDs abgebildet? |
| Volume= | Welches Host-Verzeichnis wird gemountet? |
| :U | Ändert Host-Ownership passend zum Mapping |
| :z / :Z | SELinux-Label für Bind-Mounts |
Rootless User Namespace ¶
Typisch existieren für den Host-User subordinate IDs:
/etc/subuid
alice:100000:65536
/etc/subgid
alice:100000:65536
Diese IDs stehen Podman für User Namespaces zur Verfügung.
Container-UID 1000 bedeutet daher nicht automatisch Host-UID 1000.
Beispiel:
Container UID 1000
↓
Host UID 101000
kann genauso korrekt sein wie:
Container UID 1000
↓
Host UID 1000
keep-id ¶
Für Bind-Mounts und Host-User-Ownership ist keep-id besonders interessant:
UserNS=keep-id
Damit wird die aktuelle Host-UID im Container beibehalten.
Bei Host:
UID 1000
GID 100
ergibt sich sinngemäß:
Container UID 1000 ──> Host UID 1000
Container GID 100 ──> Host GID 100
Damit kann eine Anwendung als UID 1000 im Container direkt auf Dateien zugreifen, die auf dem Host 1000:100 gehören.
Wichtig: Container-Root bei keep-id
Mit:
UserNS=keep-id
ist Container-UID 0 nicht Host-UID 1000.
Vereinfacht:
Container UID 0 ──> subordinate Host UID
Container UID 1000 ──> Host UID 1000
Daher kann folgendes passieren:
Container startet als root
↓
schreibt auf Bind-Mount
↓
Permission denied
obwohl der Prozess im Container UID 0 ist.
Container-root ist bei keep-id nicht automatisch dein Host-User.
Container mit festem App-User ¶
Wenn das Image beispielsweise als:
UID 999
GID 999
läuft, kann man keep-id parametrisieren:
UserNS=keep-id:uid=999,gid=999
User=999:999
Dann kann das Mapping sinngemäß sein:
Container 999:999 ──> Host 1000:100
Damit sieht die Anwendung intern weiterhin ihre erwartete UID:
uid=999 gid=999
während die Dateien auf dem Host 1000:100 gehören können.
Wenn der Container intern den User wechselt ¶
Beispiel:
Container startet:
UID 0 (root)
↓ su/gosu/setpriv
Anwendung:
UID 999
Das User-Switching ändert nicht das User-Namespace-Mapping.
Relevant für einen Bind-Mount ist immer der effektive User, der tatsächlich darauf zugreift.
Beispiel:
Container UID 999
↓
User Namespace
↓
Host UID 100999
oder bei entsprechendem keep-id:
Container UID 999
↓
User Namespace
↓
Host UID 1000
Bind-Mounts ¶
Bei:
Volume=/srv/app:/data
gelten weiterhin die normalen Linux-Dateirechte des Hosts:
Owner
Group
Mode
ACLs
Ein Bind-Mount hebt diese Rechte nicht auf.
Deshalb immer prüfen:
stat -c '%u:%g %a %n' /srv/app
und im Container:
id
sowie:
cat /proc/self/uid_map
cat /proc/self/gid_map
:U ≠ UID-Mapping ¶
Volume=/srv/app:/data:U
bedeutet:
Podman passt die Ownership des Host-Verzeichnisses an das Container-Mapping an.
Das kann rekursiv chown ausführen und damit tatsächlich die Ownership auf dem Host verändern.
Für das Ziel:
Host-Dateien sollen 1000:100 gehören
ist :U daher nicht automatisch die richtige Lösung.
:z / :Z ¶
Auf SELinux-Systemen sind Unix-Dateirechte nur eine Ebene.
Volume=/srv/app:/data:Z
kümmert sich um den SELinux-Kontext.
Daher können trotz korrektem:
UID = 1000
GID = 100
weiterhin Zugriffsfehler auftreten.
Empfehlenswertes Muster ¶
Wenn die Anwendung mit 1000:100 laufen kann:
[Container]
Image=...
UserNS=keep-id
User=1000:100
Volume=%h/data/app:/data:Z
Dann:
Host Container
1000:100 <──────────> 1000:100
Das ist für rootless Podman + Bind-Mounts besonders einfach und transparent.
Wenn das Image zwingend eine andere UID benötigt:
UserNS=keep-id:uid=999,gid=999
User=999:999
Dann kann beispielsweise:
Host Container
1000:100 <──────────> 999:999
verwendet werden.
Merksätze ¶
User= = Wer bin ich im Container?
UserNS= = Welche Host-Identität hat meine Container-UID?
Container-UID ≠ automatisch Host-UID.
keep-id ist besonders nützlich, wenn Container und Host dieselbe User-Identität verwenden sollen.
Der effektive User, der tatsächlich auf den Bind-Mount zugreift, ist entscheidend.
Container-root ist bei keep-id nicht dein Host-User.
UID-Mappings können nicht einfach mehrere Container-UIDs auf dieselbe Host-UID abbilden.
Bei Permission denied immer UID/GID-Mapping + Host-Dateirechte + ACL + SELinux betrachten.