[P1] Host credentials have no expiry or per-host revocation #3

Closed
opened 2026-07-02 16:43:44 +00:00 by a73x · 1 comment
a73x commented 2026-07-02 16:43:44 +00:00 (Migrated from git.a73x.sh)

[claude 2026-07-02] From architecture review (wire/auth). internal/server/hosttoken/hosttoken.go mints host credentials as host_id.HMAC-SHA256(secret,host_id). The HMAC has no timestamp/nonce, so a credential is valid forever and the only revocation is rotating the shared host_secret — which revokes the ENTIRE fleet at once. A single leaked credential = fleet-wide re-enroll.

Fix options: embed an issued-at/expiry in the credential and verify a max-age in hosttoken.Verify; and/or add a per-host token version/generation column so a single host can be revoked by bumping its version. Document the credential-compromise runbook.


Migrated from git-collab issue 9f98faa4be960f05e0a92751228c91a360a57679.

Original author: a73x dev@a73x.sh.

Close reason: Fixed by patch 1dfd9755

[claude 2026-07-02] From architecture review (wire/auth). internal/server/hosttoken/hosttoken.go mints host credentials as host_id.HMAC-SHA256(secret,host_id). The HMAC has no timestamp/nonce, so a credential is valid forever and the only revocation is rotating the shared host_secret — which revokes the ENTIRE fleet at once. A single leaked credential = fleet-wide re-enroll. Fix options: embed an issued-at/expiry in the credential and verify a max-age in hosttoken.Verify; and/or add a per-host token version/generation column so a single host can be revoked by bumping its version. Document the credential-compromise runbook. --- Migrated from git-collab issue `9f98faa4be960f05e0a92751228c91a360a57679`. Original author: a73x <dev@a73x.sh>. Close reason: Fixed by patch 1dfd9755
a73x commented 2026-07-03 13:03:57 +00:00 (Migrated from git.a73x.sh)

[claude 2026-07-03] Picking this up. Design: credential format v2 'host_id.gen.issued_unix.hmac' (HMAC over the three dotted fields). hosts table gains cred_generation (default 1, guarded ALTER migration for existing DBs); syncsvc verifies HMAC then checks gen against the host row — POST /api/v1/hosts/{id}/revoke-credential bumps gen (audited), giving PER-HOST revocation without rotating the fleet secret. issued_unix enables an optional credential_max_age server config (default off: expiry without an auto-renewal channel would force periodic re-enrolls; revocation is the primary mechanism, max-age is defense-in-depth for operators who want it). Breaking: pre-existing 2-part credentials are rejected -> agents re-enroll once (Phase-1 acceptable, documented). Old sessions: revocation takes effect at next Hello; the server also closes the host's live session on revoke.

[claude 2026-07-03] Picking this up. Design: credential format v2 'host_id.gen.issued_unix.hmac' (HMAC over the three dotted fields). hosts table gains cred_generation (default 1, guarded ALTER migration for existing DBs); syncsvc verifies HMAC then checks gen against the host row — POST /api/v1/hosts/{id}/revoke-credential bumps gen (audited), giving PER-HOST revocation without rotating the fleet secret. issued_unix enables an optional credential_max_age server config (default off: expiry without an auto-renewal channel would force periodic re-enrolls; revocation is the primary mechanism, max-age is defense-in-depth for operators who want it). Breaking: pre-existing 2-part credentials are rejected -> agents re-enroll once (Phase-1 acceptable, documented). Old sessions: revocation takes effect at next Hello; the server also closes the host's live session on revoke.
Sign in to join this conversation.
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
a73x/eitri#3
No description provided.