Secret-Datei: Container-Pfad und Dateirechte je nach Engine #3

Merged
nexus merged 3 commits from docs/secret-file-permissions into main 2026-08-04 19:24:42 +02:00
Owner

Aus dem Praxistest auf dem NAS. Drei Commits, alle zum selben Thema: HETZNER_API_TOKEN_FILE ist auf mehr als eine Art falsch zu bedienen, und keine davon war dokumentiert.

1. Der Pfad gilt im Container

HETZNER_API_TOKEN_FILE=/srv/.../hetzner_api_token mit einer Datei, die auf dem Host sichtbar dort liegt, ergab nur no such file or directory. Nichts daran deutet auf das Dateisystem des Containers — die Datei ist ja da.

Die Meldung nennt jetzt die Ursache und verweist auf den volumes-Abschnitt.

2. Die Dateirechte

Danach wartet der naechste stille Fehlschlag: Das Image laeuft nicht als Root, eine Datei von root mit 0600 ist fuer den Prozess unlesbar.

3. chown 65532 war nicht allgemeingueltig

Der urspruengliche Rat galt fuer einen rootful-Daemon. Unter rootless Podman bildet /etc/subuid die Container-UID auf eine ganz andere Host-UID ab; ein chown 65532 auf dem Host setzt dort einen Besitzer, den niemand benutzt. Die Fehlermeldung hat den Fehler wiederholt, indem sie einen fertigen chown-Befehl ausgab — der ist jetzt raus.

Die README trennt die Faelle nach User-Namespace, nicht nach Engine-Namen. Das Mapping ist keine Podman-Eigenheit: rootless Docker und --userns-remap verhalten sich genauso, rootful Podman gar nicht.

Konfiguration Mapping Vorgehen
Rootful Docker/Podman nein chown 65532:65532
Rootless Podman ja podman unshare chown 65532:0, chmod 460
Rootless Docker, --userns-remap ja kein unsharechown aus einem Wegwerf-Container

Die 0 bei unshare ist Absicht: GIDs werden ebenso abgebildet, und Container-GID 0 entspricht in der ueblichen Konfiguration der Gruppe des Host-Benutzers. 460 laesst den Container lesen und den Host-Admin weiterhin bearbeiten.

Der kuerzeste Weg, jetzt als erste Option

Beim Nachpruefen zeigte sich, dass sich das Image gar nicht auf UID 65532 festlegt: kein Benutzer-Lookup, keine Schreibzugriffe, Binary fuer alle ausfuehrbar. Es laeuft unter jeder UID. Damit genuegt in der Compose-Datei:

    user: "1000:1000"

Kein unshare, kein chown, auf jeder Engine. Steht als auskommentierte Zeile in docker-compose.yml.

Getestet

  • Beide neuen Fehlermeldungen gegen das gebaute Binary durchgespielt, dazu zwei Regressionstests
  • make lint test-race gruen, 0 Lint-Issues, Domain-Schranke gruen, keine toten Anker in der README
  • Nicht getestet: die podman unshare- und Docker-userns-remap-Kommandos. Hier ist weder Docker noch Podman installiert; die Angaben folgen der dokumentierten Semantik.
Aus dem Praxistest auf dem NAS. Drei Commits, alle zum selben Thema: `HETZNER_API_TOKEN_FILE` ist auf mehr als eine Art falsch zu bedienen, und keine davon war dokumentiert. ## 1. Der Pfad gilt im Container `HETZNER_API_TOKEN_FILE=/srv/.../hetzner_api_token` mit einer Datei, die auf dem Host sichtbar dort liegt, ergab nur `no such file or directory`. Nichts daran deutet auf das Dateisystem des Containers — die Datei ist ja da. Die Meldung nennt jetzt die Ursache und verweist auf den `volumes`-Abschnitt. ## 2. Die Dateirechte Danach wartet der naechste stille Fehlschlag: Das Image laeuft nicht als Root, eine Datei von `root` mit `0600` ist fuer den Prozess unlesbar. ## 3. `chown 65532` war nicht allgemeingueltig Der urspruengliche Rat galt fuer einen rootful-Daemon. Unter rootless Podman bildet `/etc/subuid` die Container-UID auf eine ganz andere Host-UID ab; ein `chown 65532` auf dem Host setzt dort einen Besitzer, den niemand benutzt. Die Fehlermeldung hat den Fehler wiederholt, indem sie einen fertigen `chown`-Befehl ausgab — der ist jetzt raus. Die README trennt die Faelle nach **User-Namespace**, nicht nach Engine-Namen. Das Mapping ist keine Podman-Eigenheit: rootless Docker und `--userns-remap` verhalten sich genauso, rootful Podman gar nicht. | Konfiguration | Mapping | Vorgehen | |---|---|---| | Rootful Docker/Podman | nein | `chown 65532:65532` | | Rootless Podman | ja | `podman unshare chown 65532:0`, `chmod 460` | | Rootless Docker, `--userns-remap` | ja | kein `unshare` — `chown` aus einem Wegwerf-Container | Die `0` bei `unshare` ist Absicht: GIDs werden ebenso abgebildet, und Container-GID 0 entspricht in der ueblichen Konfiguration der Gruppe des Host-Benutzers. `460` laesst den Container lesen und den Host-Admin weiterhin bearbeiten. ## Der kuerzeste Weg, jetzt als erste Option Beim Nachpruefen zeigte sich, dass sich das Image gar nicht auf UID 65532 festlegt: kein Benutzer-Lookup, keine Schreibzugriffe, Binary fuer alle ausfuehrbar. Es laeuft unter jeder UID. Damit genuegt in der Compose-Datei: ```yaml user: "1000:1000" ``` Kein `unshare`, kein `chown`, auf jeder Engine. Steht als auskommentierte Zeile in `docker-compose.yml`. ## Getestet - Beide neuen Fehlermeldungen gegen das gebaute Binary durchgespielt, dazu zwei Regressionstests - `make lint test-race` gruen, 0 Lint-Issues, Domain-Schranke gruen, keine toten Anker in der README - **Nicht getestet:** die `podman unshare`- und Docker-`userns-remap`-Kommandos. Hier ist weder Docker noch Podman installiert; die Angaben folgen der dokumentierten Semantik.
Explain a secret file path that only exists on the host
All checks were successful
CI / test (push) Successful in 1m29s
CI / image (push) Successful in 46s
e8a22ba8b3
Setting HETZNER_API_TOKEN_FILE to a host path and getting "no such file or
directory" back is a dead end: the file is plainly there, and the message
gives no reason to suspect the container's own filesystem. The path has to be
the one inside the container, with the file mounted to it.

The step after that fails just as quietly. The image runs as UID 65532, so a
root owned 0600 file is unreadable even once it is mounted.

Both failures now name the cause and the fix. The compose file spells out the
mount with the ownership command next to it, and the README shows the three
pieces — file, mount, variable — together, since getting two of the three
right still leaves it broken.
Stop prescribing chown 65532 for every engine
All checks were successful
CI / test (push) Successful in 1m29s
CI / image (push) Successful in 47s
a749b58ce7
The advice was written for a rootful daemon and is wrong under rootless
Podman, where /etc/subuid maps container UID 65532 to an unrelated host UID.
Running chown with 65532 on the host there sets an owner nobody uses. The
error message repeated the mistake by printing a ready made chown command.

Three cases, spelled out separately. Rootful keeps the plain chown. Rootless
needs podman unshare, and with GIDs mapped the same way, container GID 0 is
the group of the host user — so chown 65532:0 with mode 460 leaves the file
readable in the container and editable on the host.

Simplest of all, and now the first option offered: run the container as
whichever UID already owns the file. Nothing in the image depends on 65532 —
it writes nothing, looks up no user, and the binary is executable by all.
Separate the user namespace cases from the engine names
All checks were successful
CI / test (push) Successful in 1m31s
CI / test (pull_request) Successful in 1m38s
CI / image (push) Successful in 34s
CI / image (pull_request) Successful in 34s
33877d4446
The rootless section was headed "Rootless Podman", which reads as if the
remapping were a Podman trait. It is not: rootless Docker and a daemon started
with --userns-remap map UIDs the same way, and plain rootful Podman does not
map at all. The headings now name the namespace, not the engine.

What is Podman specific is the tool. Docker has no unshare subcommand, so the
Docker case gets the portable substitute — chown from a throwaway container,
which is already inside the right namespace.
nexus merged commit 2e56074ea6 into main 2026-08-04 19:24:42 +02:00
nexus deleted branch docs/secret-file-permissions 2026-08-04 19:24:42 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nexus/hetzner-ddns!3
No description provided.