secrets-engine/docs/founder-admission.md
tegwick ebd8e49aff
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s
feat(admission): founder-signed trust and recovery-attempt admission (WP14 T02, WP15 T05)
Reuse the gated-executor approval pattern: ssh-keygen -Y signatures over exact
bytes, verified against a runtime-unwritable allowed_signers anchor with a fixed
namespace per purpose. load_trust now refuses responder trust without a founder
admission; the KeyCape selector preflight gains --admission for one exact,
bounded recovery attempt. WP14 re-pointed to CUST-WP-0082-T06 and split founder
key admission into human-gated T04; WP15 T04 now requires the signed admission.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 809600@bnt-lap001
Assistant-Session: 40ba228f-c8a0-4ec9-bb29-3129951afdc4
2026-10-21 00:30:59 +02:00

3 KiB

Founder admission (SSH signature over exact bytes)

Two inputs need authority from outside this process: the Access Engine responder trust file (SECRETS-WP-0014) and a KeyCape recovery attempt (SECRETS-WP-0015). The runtime itself must not be able to grant either. Both now use the approval pattern the estate already accepted in gated-executor (GEXEC-WP-0001, installed on railiance01 2026-10-20). The founder signs exact bytes with the passphrase-protected key, and the verifier trusts only an allowed_signers file that the runtime account cannot write.

Implementation: src/secrets_engine/founder_admission.py. No new approval service, network call or key type is involved. ssh-keygen -Y works offline, so the recovery case still works when KeyCape/OpenBao are down.

Anchor

/etc/secrets-engine/admission/            root:root 0755
/etc/secrets-engine/admission/allowed_signers   root:root 0644

SECRETS_ENGINE_ADMISSION_ANCHOR may name another directory. The checks stay the same either way: the directory and file are not symlinks, not group/world writable, and not owned by the running UID unless that UID is root. The signer principal is read from the signature (find-principals), and it must match exactly one allowed_signers entry.

Namespaces are fixed per purpose, so a signature for one purpose cannot admit another. That includes a gexec action approval (gexec-approval).

Purpose Namespace Signed file Signature
PDP responder trust secrets-engine-pdp-trust pdp-trust.json pdp-trust.json.sig
Recovery attempt secrets-engine-recovery-attempt attempt admission JSON <file>.sig

Admit or rotate responder trust

ssh-keygen -Y sign -f ~/.ssh/<founder-key> -n secrets-engine-pdp-trust pdp-trust.json

load_trust verifies the signature over the same bytes it parses. Any edit needs a new signature, so rotation means a newly signed file. Overlap is two keys in one signed file, and removal is a signed file without the old key. Neither the file's presence nor a loopback URL counts as admission.

Admit one recovery attempt

{"schema": "secrets-engine.recovery-attempt-admission.v1",
 "selector_sha256": "sha256:<exact selector file bytes>",
 "source_sha256": "sha256:<service_auth.py>",
 "issuer": "https://kc.coulomb.social",
 "case": "secrets15-nk49-readiness",
 "not_before": "YYYY-MM-DDTHH:MM:SSZ", "not_after": "YYYY-MM-DDTHH:MM:SSZ"}
ssh-keygen -Y sign -f ~/.ssh/<founder-key> -n secrets-engine-recovery-attempt attempt.json
tools/check-keycape-recovery-selector.py --selector docs/keycape-recovery-selector.json \
  --source-sha256 sha256:<...> --admission attempt.json

The window may be at most 24 hours. A pass reports founder_admitted_attempt_not_native_acceptance. That status proves the founder admitted this exact attempt. It does not prove the attempt ran, that it ran only once, or that the native result passed. Single-use consumption and cleanup stay with the bounded NK-WP-0049 execution process.