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.
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
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary generated by LLM agent
Fixes
Load key "/run/secrets/guard_key": Permission deniedfollowed byPermission 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
chownand explains why it is not optional.The guard says it itself
ssh_keyis 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 exactchownthat 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
Dockerfilewith an explicitgroupadd --gid, rather than left to whateveruseraddchose, because it is a number the README now tells operators tochownto. 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.