RPF-WP-0064: owner answers for NK-WP-0049-T43 (JWT trust fields, phase B names, phase A acceptance)
All checks were successful
CCR intake gate / gate (push) Successful in 11s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4515@bnt-lap001
Assistant-Session: 0bf96127-6e04-41be-bfda-d11717c3f354
This commit is contained in:
codex 2026-10-27 21:40:59 +01:00
parent 2bbf1ffd83
commit 565815006c

View file

@ -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=<attempt-id>`) | `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:<worker>`), 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.