diff --git a/workplans/RPF-WP-0064-isolated-original-openbao-restore.md b/workplans/RPF-WP-0064-isolated-original-openbao-restore.md index f0518f7..0511f3e 100644 --- a/workplans/RPF-WP-0064-isolated-original-openbao-restore.md +++ b/workplans/RPF-WP-0064-isolated-original-openbao-restore.md @@ -508,3 +508,77 @@ depends_on: [RPF-WP-0064-T08] Phase B source preparation: implement items 1-9 above as a separate mode, rehearse natively with synthetic material, obtain owner review and the new pin, then wait for a new founder-signed phase B window (T05-style admission). No live run is part of this task. + +## Owner answers to NK-WP-0049-T43 (2026-10-27, reply to net-kingdom message 43a545e2) + +Source and value-free evidence only. No docker, kubectl or OpenBao action; no value read. + +**1. `keycape-services` JWT trust fields (presence only).** + +| Field | Committed source (`openbao/auth/keycape-services-config.json`) | Restored original (T07 `-03` receipt) | +| --- | --- | --- | +| `jwks_url` | present | **proven** present and equal to source | +| `jwks_ca_pem` | absent | not proven either way | +| `oidc_discovery_url` | absent | inferred absent | +| `oidc_discovery_ca_pem` | absent | not proven either way | + +- Proven: the source file has three keys only (`bound_issuer`, `jwks_url`, `jwt_supported_algs`). The + `-03` receipt matched the restored config to the source, but `restore_adapter.project()` compares only + keys present in the source file. Extra restored fields are not covered by the receipt. +- Inferred, high confidence: the CCR-2026-0038 applier writes the whole file + (`bao write auth/keycape-services/config @file`, `scripts/service_jwt_lane.py`). A config write replaces the + stored config, so both CA fields were unset when it was applied. OpenBao also refuses `jwks_url` together + with `oidc_discovery_url`, so the proven `jwks_url` excludes a discovery URL. A later out-of-band write is not + excluded by the evidence. The `netkingdom` mount (operator path, not used in phase B) uses + `oidc_discovery_url` and has no `oidc_discovery_ca_pem` in source. +- Consequence: JWKS fetch trust comes from the image's system CA bundle. + +**ISRG Root X1 in the pinned image (`sha256:436eaf97…c115`).** Not proven, and the bundle was not inspected. +Inferred: the production pod used this config, with no CA field, for the live login proof on 2026-10-10. Writing +the config with JWKS validation also needs a TLS fetch. So the production image trusted the chain then served +for `kc.coulomb.social` through its system roots. This assumes the chain is Let's Encrypt, which is not recorded +in this repo, and that the 2026-10-10 image digest equals the T06 pin, which is not proven. +Settle both in the phase B native rehearsal (T09 item 8): run a value-free `/jwks` fetch from the pinned image +against the real `letsencrypt-prod` chain served on the internal network, and record the result, the chain's +root subject and whether a CA field is set. Add a presence-only check of the four fields to the phase B readback. + +**2. Proposed phase B names, so the attached-set check can match.** + +| Item | Live window | Synthetic rehearsal | +| --- | --- | --- | +| Network (`--internal`, IPv4 only, label `railiance.rpf64.attempt=`) | `rpf64-nk49-pb` | `rpf64-nk49-pb-rh` | +| Subnet | `10.249.64.0/28` | `10.249.65.0/28` | +| Restored OpenBao: container, alias, IP | `rpf64-nk49-pb-openbao`, `bao-restored`, `.2` | `rpf64-nk49-pb-rh-openbao`, same alias | +| Isolated KeyCape worker (NetKingdom): container, alias, IP | `nk49-pb-keycape`, `kc.coulomb.social`, `.3` | `nk49-pb-rh-keycape` | +| Consumer runner (secrets-engine): container, IP | `secrets15-pb-consumer`, `.4` | `secrets15-pb-rh-consumer` | +| Egress probe (railiance-platform; removed before KeyCape attaches) | `rpf64-nk49-pb-probe` | `rpf64-nk49-pb-rh-probe` | + +- Admitted attached set after the probe is removed: exactly the three named containers, in the order network, + probe and removal, KeyCape, OpenBao, consumer. +- KeyCape's dependent containers share the worker namespace (`container:`), so they are not attached + separately. +- Fixed IPs (`--ip`) make the attached-set and route checks exact. The subnet avoids Docker's default pools and + k3s `10.42/10.43`; preflight refuses on any overlap with a host route. +- `--internal` still gives the host bridge an address. Whether to add + `com.docker.network.bridge.inhibit_ipv4=true` ("no gateway") is decided in the rehearsal. Until then, the + check is no default route plus refused egress. +- Names are proposals. Each owner's admission binds them. + +**3. Phase A evidence as T15's OpenBao dependency (platform-owner view, builder mode).** +Acceptable. Original material restored in isolation: cluster id matched, applied index not behind, the founder's +original shares unsealed it, and all nine required objects matched source (mounts, both auth configs, both +roles, policy, KV metadata). The receipt was independently verified from a clean clone, with containment and +teardown proven. That is proportionate for a builder-mode estate. + +Named residuals: +- (R1) Config match is a projection over source keys; extra fields such as the CA fields are unproven. +- (R2) No live JWT login against the restored target. That is phase B, T09. +- (R3) The operator OIDC path was checked by config and role readback only, with no interactive login. +- (R4) KV metadata only, by design. Value integrity is not shown. +- (R5) The snapshot dates from 2026-10-14. That the image digest at snapshot time equals the pin is not proven. +- (R6) This was one attended restore, not recurring assurance (RPF-WP-0036-T03). +- (R7) The receipt is a single copy outside Git on the founder workstation, referenced by hash `4e048dee…579d`. +- (R8) Restore depends on the file audit-device mount (found and fixed in `-02`/`-03`). Any future target needs it. + +None of these blocks T15's OpenBao line. R1/R2 close in phase B. This is not owner acceptance of the full T15 +packet or of the other three services.