docs(research): client host-key policy resolved to a two-case policy seam
- OQ-05 resolved: known-beforehand hosts (assembly-minted/family runners) -> pinned, hard-decline on mismatch; unknown-beforehand hosts (rental fleets) -> assembly-provided HostKeyPolicy the crate calls — prompt- record, provider-metadata match, or learn-and-record. Crate default stays fail-closed reject-unknown; crate never decides trust; storage of learned pins is assembly detail - auth-bridge.md: refinement postscript — no-TOFU is a no-trust-decisions- -in-crate rule, not pin-everything; alkminer's accept-all was the fleet- churn collapse, and the real anchor for ephemeral fleets is hub-held key material, not host pins - reverse-runner.md §5 rewritten with the same nuance
This commit is contained in:
1 parent
644269b258
commit
04f48ab9bc
3 files changed
+34
-10
No files matched your search
@@ -54,14 +54,17 @@ alkcall trackers have their own OQ spaces).
|
||||
|
||||
## Theme C — auth, identity & key custody
|
||||
|
||||
### OQ-05: What is the client-side host-key pin store?
|
||||
### OQ-05: ~~What is the client-side host-key pin store?~~ — resolved (policy-seam shape)
|
||||
|
||||
- **Origin**: [auth-bridge.md](../research/auth-bridge.md) §Host keys, `reverse-runner.md` §5
|
||||
- **Status**: open
|
||||
- **Priority**: high
|
||||
- **Impacts**: blocks the `client.md` dial surface (the `check_server_key` policy and its configuration seam) and any alkforge reverse-runner deployment (every dial needs a pinned host).
|
||||
- **Resolution**: pending. The no-TOFU rule is fixed; candidates are the family identity registry vs an assembly-supplied pin set vs `check_known_hosts`. Decide when `client.md` is written — the reverse-runner evidence (chalk-full accept-all in old code) is the anti-pattern witness, not the precedent.
|
||||
- **Cross-references**: ADR-004, OQ-07
|
||||
- **Status**: resolved — the *seam* is decided; where learned pins persist is assembly detail (the crate takes a policy, not a pin store).
|
||||
- **Resolution**: two basic client cases, one seam:
|
||||
|
||||
1. **Known beforehand** — trust anchors exist. Family-built runners mint their host key at assembly time, so the expected fingerprint is known before first contact: assembly-supplied pins, **hard decline on mismatch** (no soft failure).
|
||||
2. **Unknown beforehand** — vanilla `sshd` on container fleets the assembly didn't provision; no anchor exists until first contact. The crate surfaces the presented host key (host, port, fingerprint) to an **assembly-provided `HostKeyPolicy`** that decides: prompt-and-record, provider-metadata match, or learn-and-record. The OpenSSH "add to known_hosts?" moment becomes an assembly policy rather than crate behavior.
|
||||
|
||||
Crate rules that make this family-shaped: the crate's default policy is **fail-closed** (reject unknown, hard-decline mismatch — russh's own reject-all default, kept); the crate never decides trust itself; accept-all is never a crate option (that collapse is the old-code anti-pattern, and for ephemeral fleets strict pinning is the wrong control anyway — the anchor there is hub-held key material/lifecycle, not host pins). The contract lands in the client-side ADR (written with `client.md`; expected to be ADR-007) and the `auth.md` spec.
|
||||
- **Cross-references**: OQ-07, `reverse-runner.md`, [poc-2-vault-keys.md](../research/poc-2-vault-keys.md) §5 (host keys ride the vault model)
|
||||
|
||||
### OQ-06: ~~One vault, many roles?~~ — resolved
|
||||
|
||||
|
||||
@@ -196,6 +196,19 @@ russh, but the family identity registry is likely the better pin store
|
||||
(RSA-AKCE-style proving, new in 0.64.0) is an optional hardening note
|
||||
for the ADR.
|
||||
|
||||
**Post-POC refinement (client-direction host-policy cases; see
|
||||
`reverse-runner.md` and OQ-05 in the architecture tracker):** the
|
||||
no-TOFU rule is a rule about trust *anchors*, not an absolute. Two
|
||||
client cases: (1) hosts the assembly controls or can provision — the
|
||||
host key is knowable beforehand (family-built runners mint theirs at
|
||||
assembly time) → pinned, hard-decline on mismatch; (2) hosts that are
|
||||
unknown until first contact (rental-fleet vanilla `sshd`) → the
|
||||
OpenSSH "add to known_hosts?" moment becomes an assembly-provided
|
||||
*host-key policy seam* the crate calls with (host, port, fingerprint);
|
||||
the crate default is fail-closed (reject unknown), never auto-trust,
|
||||
never accept-all. Trust policy is the assembly's; the crate is
|
||||
policy-blind.
|
||||
|
||||
## References
|
||||
|
||||
- alkcall: `src/core/auth.rs` (Identity/AuthToken/AuthContext/
|
||||
|
||||
@@ -78,10 +78,18 @@ One authenticated SSH connection per instance carried:
|
||||
5. **Host-key pinning anti-pattern.** alkminer's `check_server_key`
|
||||
returned accept-all (TOFU-without-the-F, 0.62 default posture
|
||||
overridden to the permissive extreme for rental fleets). The family
|
||||
rule (no TOFU; expected host fingerprints pinned at the assembly
|
||||
layer) is right, and this code is the working exhibit of why. The
|
||||
*convenience* need is real (fleets churn); the resolution is
|
||||
pinning policy at the assembly, not accept-all in the crate.
|
||||
rule: no trust decisions inside the crate — default fail-closed,
|
||||
trust via an assembly-provided policy seam. The lesson is sharper
|
||||
than "pin everything", though: for *ephemeral* fleets strict TOFU
|
||||
is unusable anyway (fresh container each rent → fresh host key;
|
||||
the churn is exactly why accept-all won), so the real security
|
||||
anchor there is hub-held key material (per-instance dial keys make
|
||||
a captured hub credential worthless) plus what rides the tunnels;
|
||||
host pinning is the right control only where anchors can exist
|
||||
(family-built runners, whose host key the assembly mints and
|
||||
therefore knows beforehand). The fleet churn is the reason the
|
||||
two-case policy seam (OQ-05) is the correct shape rather than
|
||||
"pin everything".
|
||||
6. **Per-runner key registration.** Keys were minted per instance and
|
||||
registered hub-side (their provisioning flow, including a real
|
||||
gitea client for dev workspaces) — the deployment precedent for
|
||||
|
||||
Reference in new issue
Block a user