Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: sonnet Assistant-Process: 628290@bnt-lap001 Assistant-Session: 70de878b-b4e0-4110-a1ec-bbd553a5f483
8.5 KiB
NK49 phase B: isolated KeyCape and restored OpenBao on one internal network
NK-WP-0049-T43. Drafted 2026-10-24. Preparation only. This grants no authority, starts nothing and is not T18 acceptance. Every number marked proposed is a suggestion for the owners, not a fact.
Purpose
T18 needs a live consumer login against restored dependencies. The consumer is
secrets-engine's secrets-engine-openbao workload (SECRETS-WP-0015-T04): it obtains
a token from KeyCape, then logs in to OpenBao with the JWT role. Today the two
recovered pieces cannot meet:
| Piece | State | Network today |
|---|---|---|
| Isolated original KeyCape (NK49 T18 attempt) | Verified 2026-10-23, receipt 16d72f7c…1651, then destroyed |
--network none; TLS served on its own loopback |
| Restored original OpenBao (RPF-WP-0064-T07) | Verified 2026-10-24, receipt 4e048dee…579d, then destroyed |
--network none; listener on 127.0.0.1:8200 only |
OpenBao's keycape-services JWT auth validates against https://kc.coulomb.social/jwks.
A networkless OpenBao proves configuration but cannot perform the login. Phase B is the
shared network that lets it.
Proposed topology
docker network create --internal (no gateway, no published ports)
┌───────────────────────────────────────────────────────────────────────┐
│ keycape-worker alias kc.coulomb.social :443 TLS ─▶ issuer :8080 │
│ (+ issuer sharing its namespace, as in the T18 attempt) │
│ │
│ restored OpenBao alias bao-restored :8200 (unsealed, same window)│
│ │
│ consumer runner (secrets-engine owned; the only client) │
└───────────────────────────────────────────────────────────────────────┘
no other attachment · egress shown refused before admission
Who owns what
| Step | Owner | Notes |
|---|---|---|
| Create and tear down the internal network | Proposed: railiance-platform | Its design stub already says phase B is "a single docker network create --internal network". One creator avoids a double teardown. |
| Restore and unseal original OpenBao, keep it up for the window | railiance-platform | Adapter runs phase A, then does not tear down when phase B is admitted in the same window (its doc). Needs a listener on the internal address, not loopback only. |
| Start the isolated original KeyCape on that network | NetKingdom (this plan) | Needs a new variant of the T18 machinery; see below. |
Consumer login: KeyCape exchange, OpenBao JWT login, openbao:admin refusal, session revocation |
secrets-engine | SECRETS-WP-0015-T04. |
ACME issuance for kc.coulomb.social |
railiance-cluster | Existing owner of the T33 reissue. |
| Window, abort, and every signature | founder | One window, several admissions. |
What NetKingdom must change (verified from current source)
The T18 machinery is pinned: prepare-isolated-keycape.py lists isolated-keycape.py,
isolated-keycape-session.py, run-isolated-keycape.sh, isolated-lldap.py,
identity-bundle.py, verify-identity.py and others as the reviewed source closure,
and the T38 review and T40 admission bind their hashes. They must stay unedited.
Phase B is therefore a new module beside them, with its own review.
Facts read from the code that force changes:
isolated-keycape-session.pylaunches the worker with--network noneand--add-host kc.coulomb.social:127.0.0.1. Phase B needs the worker on the internal network with--network-alias kc.coulomb.social.isolated-keycape.pyinspect_sessionrefuses any worker whoseNetworkModeis notnone, and checks that dependent containers havecontainer:<worker>. A phase B variant must accept exactly one named internal network and verify, by inspection, that it isInternal=true, that its attached set is exactly the admitted containers, and that the worker has a subnet route but no default route.- The probes assert that only
loexists and/proc/net/routehas one line. In phase B an interface and a subnet route exist by design, so "no external route" must be proved differently: no default route,Internal=true, and refused egress probes (to a public address and to a name outside the admitted aliases). verify-keycape-attempt-receipt.pyexpects thenonetopology and must have a phase B counterpart, so the receipt can still be verified independently.- The T40 admission window ended 2026-10-24T05:00Z. Phase B needs a new founder signature; nothing signed before carries over.
Proposed new files (names are suggestions): isolated-keycape-phase-b.py,
run-isolated-keycape-phase-b.sh, verify-keycape-phase-b-receipt.py, tests, and a
packet section. Effort is moderate to large and touches the most sensitive machinery
here, so it should get the same review depth as T38, not a quick patch.
Preconditions and ordering (proposed)
- Owners each pass their own preflight (RPF-WP-0064 adapter, the secrets-engine
selector with
--admission, NK49prepare-style validation). - One founder window, at most 24 h (owner admission rules). OpenBao's own deadline is 45 minutes from its first custody input, so OpenBao is started last among the long-lived pieces and the consumer run follows immediately.
- railiance-platform creates the network and shows egress refusal.
- NK49 starts the isolated KeyCape (age key, TLS key and trust in the founder's terminal, as in the T18 ceremony).
- railiance-platform restores and unseals OpenBao onto the same network.
- secrets-engine runs the consumer login.
- Teardown in reverse; each owner returns a safe receipt. The network creator removes the network last and shows it gone.
Evidence and claims
Returned: NK49 phase B receipt (verified independently), railiance-platform's phase B
receipt, secrets-engine's consumer result. Together they would show, with no secret
values: the original issuer and signing key served over TLS on the internal network;
openbao:login accepted; openbao:admin refused; wrong secret refused; a session
revoked; egress refused; cleanup of containers, tmpfs and network.
Not claimed: production continuity or redirect, new grants, a live OpenBao read of
secret data (platform/workloads/keycape/secrets-engine-openbao stays metadata only),
human login through Authelia, or owner acceptance. T18 also needs its owner acceptance.
Decisions (answered 2026-10-27; decision e4db6c9f) and remaining owner items
Founder answers: 1 railiance-platform creates the network; 2 reissue via letsencrypt-prod once railiance-cluster confirms the duplicate count (no self-signed, no retained key); 5 one workload consumer suffices, no Authelia. Item 3 (secret custody) is secrets-engine's to propose and item 4 (ISRG trust) is confirmed in the owner rehearsal. The answers authorize nothing; windows and signatures stay separate.
- Network creator. railiance-platform (proposed) or NetKingdom?
- TLS identity. The T18 attempt reissued
kc.coulomb.socialthroughletsencrypt-prodand destroyed the key. Phase B needs a certificate again: reissue (consumes the duplicate-certificate allowance, limit 5 per week; railiance-cluster should confirm the count) or retain the key from the earlier attempt (a custody decision). No self-signed substitute is allowed (decision9f9d0d88). - Consumer secret custody. The consumer's client secret
keycape-secrets-engine-openbao-clientis in the backup's KeyCape secrets. How does the consumer runner receive it without the agent, argv or files seeing it? This is secrets-engine's design to propose; NetKingdom must not hand it over implicitly. - Trust in OpenBao. The restored OpenBao must trust the ISRG Root X1 chain to
fetch
/jwks. Confirm in the owner's rehearsal rather than assume. - Scope. Is this one workload consumer enough for T18's "selected current consumer", or must a human-login consumer also be admitted? This plan assumes the workload consumer and does not require Authelia in phase B.
Unsigned admission
docs/nk49-phase-b-admission.example.json is a template with placeholders. It is not
signed, names no real hashes for unwritten files and authorizes nothing.