fix(deploy): provision the certs dir traversable by the nonroot gateway #238

Merged
developer merged 1 commits from fix/ansible-certs-dir-traversable into development 2026-07-10 10:39:06 +00:00
Owner

Root-cause fix for the prod gateway crash-loop hit during the v1.14.0 deploy.

The Ansible base-directory loop created /opt/scrabble/certs at 0750 (deploy:deploy), like config/dumps/images. The gateway/backend run as the distroless nonroot UID 65532 (not the deploy user), so the container can't traverse a 0750 certs dir → mtls: load server keypair: ... permission denied → crash-loop.

Latent: a long-running container holds the keypair in memory and never re-reads the file, so it only bites on a container restart. A hoster maintenance reboot restarted the gateway and exposed it (the files were 0644 all along — the memory rule — but the dir blocked traversal).

Splits certs out of the 0750 loop → 0755 (traversable). Keys stay 0644 by design; the host is single-tenant + SSH-access-controlled. The live prod host was already hand-fixed (chmod 0755); this keeps the next provisioning run from re-tightening it.

No app code; Ansible-only (applies on the next manual provisioning run).

Root-cause fix for the prod gateway crash-loop hit during the v1.14.0 deploy. The Ansible base-directory loop created `/opt/scrabble/certs` at **0750** (deploy:deploy), like config/dumps/images. The gateway/backend run as the distroless **nonroot UID 65532** (not the deploy user), so the container can't traverse a 0750 certs dir → `mtls: load server keypair: ... permission denied` → crash-loop. **Latent:** a long-running container holds the keypair in memory and never re-reads the file, so it only bites on a container **restart**. A hoster maintenance reboot restarted the gateway and exposed it (the files were 0644 all along — the memory rule — but the **dir** blocked traversal). Splits `certs` out of the 0750 loop → **0755** (traversable). Keys stay 0644 by design; the host is single-tenant + SSH-access-controlled. The live prod host was already hand-fixed (`chmod 0755`); this keeps the next provisioning run from re-tightening it. No app code; Ansible-only (applies on the next manual provisioning run).
developer added 1 commit 2026-07-10 10:34:34 +00:00
fix(deploy): provision the certs dir traversable by the nonroot gateway
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 19s
CI / ui (pull_request) Successful in 1m11s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m54s
2d2dd2bc47
The Ansible base-directory loop created /opt/scrabble/certs at mode 0750
(deploy:deploy), like config/dumps/images. The gateway (and backend) run as
the distroless nonroot UID 65532 — not the deploy user — so the container
cannot traverse a 0750 certs dir and fails at startup with
"mtls: load server keypair: ... permission denied", crash-looping.

This is latent: a long-running container holds the keypair in memory and
never re-reads the file, so the misconfig only bites when a container
restarts (a host reboot / redeploy). A hoster maintenance reboot exposed it
on prod — the gateway came back crash-looping while the deploy could not SSH
in mid-reboot.

Split certs out of the 0750 loop and create it 0755 (traversable). The keys
stay 0644 by design (the gateway compose relies on it); the host is
single-tenant + SSH-access-controlled, so a traversable certs dir adds no
meaningful exposure. The live prod host was already chmod-fixed by hand; this
keeps the next provisioning run from re-tightening it.
owner approved these changes 2026-07-10 10:36:18 +00:00
developer merged commit 2683103fc1 into development 2026-07-10 10:39:06 +00:00
developer deleted branch fix/ansible-certs-dir-traversable 2026-07-10 10:39:06 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: developer/scrabble-game#238