Check the guard can read its own key, and say so when it cannot #10

Merged
branderson merged 1 commits from key-readable into main 2026-08-28 20:48:14 -07:00
Collaborator

Summary generated by LLM agent

Fixes Load key "/run/secrets/guard_key": Permission denied followed by Permission denied (publickey,password) on a deployment built exactly as the README describes.

The setup instructions caused it

The image runs as uid 10001 rather than root. Compose bind-mounts a file secret with the host's ownership and mode. The README said to chmod 600 secrets/guard_key, which leaves it readable only by the operator's own account — so the container cannot open its own key.

ssh reports an unreadable key as Permission denied (publickey,password), which is exactly what a devbox that rejected the key says. Nothing distinguishes the two, so the failure points at the far end while the fault is a file on this one.

The setup now does the chown and explains why it is not optional.

The guard says it itself

ssh_key is checked for existence and readability before anything connects. The message carries the uid this is running as, the file's ownership and mode, and the exact chown that fixes it — phrased around the running uid rather than claiming "the image runs as", which would be false whenever it is not in a container.

The cycle stops there rather than alerting. A file on this machine is not a finding about the watched one, and reporting it as such sends the operator to the wrong host. No heartbeat goes out either: a guard that cannot use its key is not watching, and the silence is what the dead-man's switch exists to report.

The uid is now an interface

Pinned in the Dockerfile with an explicit groupadd --gid, rather than left to whatever useradd chose, because it is a number the README now tells operators to chown to. A test holds the two files together — a uid that moved between them would produce this exact failure while the documentation insisted it had been dealt with.

Tested: 63 passing, including one that a non-existent or unreadable key produces no alert and no heartbeat.

**Summary generated by LLM agent** Fixes `Load key "/run/secrets/guard_key": Permission denied` followed by `Permission denied (publickey,password)` on a deployment built exactly as the README describes. ## The setup instructions caused it The image runs as uid 10001 rather than root. Compose bind-mounts a file secret with the host's ownership and mode. The README said to `chmod 600 secrets/guard_key`, which leaves it readable only by the operator's own account — so the container cannot open its own key. ssh reports an unreadable key as `Permission denied (publickey,password)`, which is exactly what a devbox that rejected the key says. Nothing distinguishes the two, so the failure points at the far end while the fault is a file on this one. The setup now does the `chown` and explains why it is not optional. ## The guard says it itself `ssh_key` is checked for existence and readability before anything connects. The message carries the uid this is running as, the file's ownership and mode, and the exact `chown` that fixes it — phrased around the running uid rather than claiming "the image runs as", which would be false whenever it is not in a container. The cycle stops there rather than alerting. A file on this machine is not a finding about the watched one, and reporting it as such sends the operator to the wrong host. No heartbeat goes out either: a guard that cannot use its key is not watching, and the silence is what the dead-man's switch exists to report. ## The uid is now an interface Pinned in the `Dockerfile` with an explicit `groupadd --gid`, rather than left to whatever `useradd` chose, because it is a number the README now tells operators to `chown` to. A test holds the two files together — a uid that moved between them would produce this exact failure while the documentation insisted it had been dealt with. Tested: 63 passing, including one that a non-existent or unreadable key produces no alert and no heartbeat.
dejima-agent added 1 commit 2026-08-28 20:36:19 -07:00
The container runs as uid 10001, compose mounts a file secret with the host's
ownership and mode, and the setup instructions said to chmod 600 a key owned by
the operator. So a deployment built exactly as documented could not open its own
key, and ssh reports that as "Permission denied (publickey,password)" - the same
thing a devbox that rejected the key says. The operator is sent to the far end
to debug a file on this one.

The key is checked before connecting, with the uid this runs as, the file's
ownership and mode, and the chown that fixes it. The setup does the chown now,
and says why it is not optional.

The uid is pinned in the Dockerfile with an explicit gid rather than whatever
useradd picks, because it is now a number written in the README that operators
chown to. A test holds the two together: a uid that moved between them would
produce this exact failure with the documentation insisting it was handled.

The cycle stops rather than alerting. A file on this machine is not a finding
about that one, and no heartbeat goes out - a guard that cannot use its key is
not watching, which is what the dead-man's switch exists to report.
branderson approved these changes 2026-08-28 20:47:49 -07:00
branderson merged commit 95efc90497 into main 2026-08-28 20:48:14 -07:00
Sign in to join this conversation.