Skip to content

fix: chmod the owned /etc/hosts world-readable for non-root images#81

Merged
lesnik512 merged 2 commits into
mainfrom
fix/world-readable-hosts-file
Jul 22, 2026
Merged

fix: chmod the owned /etc/hosts world-readable for non-root images#81
lesnik512 merged 2 commits into
mainfrom
fix/world-readable-hosts-file

Conversation

@lesnik512

@lesnik512 lesnik512 commented Jul 22, 2026

Copy link
Copy Markdown
Member

Problem

A 0.4.0-generated script writes the pod's owned /etc/hosts via hostsfile=$(mktemp) — mode 0600, owned by the invoking user — and bind-mounts it read-only into every container. A service image that runs as a non-root user cannot read a 0600 root-owned file, so glibc skips /etc/hosts, falls through to DNS, and pod-internal name resolution fails:

sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) could not translate
host name "db" to address: Temporary failure in name resolution

Root-user images were unaffected, which is why the 0.4.0 owned-/etc/hosts mechanism passed validation — every probe ran as root. This bites any real-world image with a USER directive (the common case in corporate CI).

Fix

Emit chmod 644 "$hostsfile" immediately after the printf that writes the file and before the first podman run mounts it. The file holds only hostname → 127.0.0.1 and extra_hosts (hostname → ip) lines — nothing secret — so world-readable is correct. umask cannot substitute: mktemp forces 0600 regardless.

Verification

  • Reproduced on real Podman 5.8.1 (quay.io/podman/stable:v5.8.1): a non-root member gets cat: /etc/hosts: Permission denied + socket.gaierror without the chmod; resolves db → 127.0.0.1 with it.
  • End-to-end: fixed generator's script runs a user: "1000" app that resolves db on 5.8.1.
  • TDD: failing unit test first (test_hosts_file_made_world_readable), then fix.
  • just test-ci — 1402 passed, 100% coverage. just lint-ci — clean.

Rationale: planning/changes/2026-07-22.01-world-readable-hosts-file.md. Architecture promoted in architecture/supported-subset.md (owned-/etc/hosts bullet).

Bundled: ty 0.0.62 lint fix (2nd commit)

CI resolves ty fresh each run (uv.lock is git-ignored), and 0.0.62 tightened sorted()'s bound so the 11 pre-existing sorted(set(mapping) - KNOWN) unsupported-key paths (set[object] is not SupportsRichComparison) broke lint — unrelated to the hosts fix but blocking every PR. require_string_keys already proves keys are str; it now returns them as set[str] so each check consumes a statically sortable set. No runtime behavior change.

mktemp creates the script-owned hosts file 0600, owned by the invoking
user. Bind-mounted read-only as /etc/hosts, a service image running as a
non-root user cannot read it: glibc skips /etc/hosts, falls through to
DNS, and pod-internal name resolution fails with "could not translate
host name: Temporary failure in name resolution". Root-user images were
unaffected, which is why the 0.4.0 owned-/etc/hosts mechanism passed
validation.

Emit chmod 644 on the hosts file after writing it and before the first
podman run mounts it. The file holds only hostname/extra_hosts lines, so
world-readable is correct. Reproduced and fixed against real Podman
5.8.1.
ty 0.0.62 tightened sorted()'s bound: set(mapping) over an untyped
compose mapping infers set[object], which does not satisfy
SupportsRichComparison, so the 11 unsupported-key error paths that do
sorted(set(mapping) - KNOWN) failed the type gate. require_string_keys
already proves every key is str; have it return the keys as set[str] so
each check builds on a statically sortable type (require_string_keys(...)
- KNOWN) and drops a redundant re-iteration. No runtime behavior change.
@lesnik512
lesnik512 merged commit 95be192 into main Jul 22, 2026
8 checks passed
@lesnik512
lesnik512 deleted the fix/world-readable-hosts-file branch July 22, 2026 11:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant