RPF-WP-0064: propose isolated original-OpenBao restore for SECRETS-WP-0015-T04
Accepts hub request 41e9af3e as source preparation. T01 source survey recorded and done; restore and consumer continuity stay unclaimed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 4384@bnt-lap001 Assistant-Session: 80d1f3da-7a91-4519-9737-9ba128b4da64
This commit is contained in:
parent
1f8fbc7584
commit
3894dc7c54
2 changed files with 271 additions and 0 deletions
|
|
@ -43,6 +43,7 @@
|
|||
| workplan | RPF-WP-0061 | active | — | workplans/RPF-WP-0061-self-service-ccr-intake.md |
|
||||
| workplan | RPF-WP-0062 | finished | — | workplans/RPF-WP-0062-custodian-agent-observer-identity.md |
|
||||
| workplan | RPF-WP-0063 | finished | — | workplans/RPF-WP-0063-wave2-resource-right-sizing.md |
|
||||
| workplan | RPF-WP-0064 | proposed | — | workplans/RPF-WP-0064-isolated-original-openbao-restore.md |
|
||||
| task | RPF-WP-ADHOC-2026-10-10-T01 | done | — | workplans/ADHOC-2026-10-10.md |
|
||||
| task | RPF-WP-ADHOC-2026-10-11-T01 | done | — | workplans/ADHOC-2026-10-11.md |
|
||||
| task | RPF-WP-ADHOC-2026-10-11-T02 | done | — | workplans/ADHOC-2026-10-11.md |
|
||||
|
|
@ -192,6 +193,14 @@
|
|||
| task | RPF-WP-0062-T02 | done | — | workplans/RPF-WP-0062-custodian-agent-observer-identity.md |
|
||||
| task | RPF-WP-0062-T03 | done | — | workplans/RPF-WP-0062-custodian-agent-observer-identity.md |
|
||||
| task | RPF-WP-0063-T01 | done | — | workplans/RPF-WP-0063-wave2-resource-right-sizing.md |
|
||||
| task | RPF-WP-0064-T01 | done | — | workplans/RPF-WP-0064-isolated-original-openbao-restore.md |
|
||||
| task | RPF-WP-0064-T02 | todo | — | workplans/RPF-WP-0064-isolated-original-openbao-restore.md |
|
||||
| task | RPF-WP-0064-T03 | todo | — | workplans/RPF-WP-0064-isolated-original-openbao-restore.md |
|
||||
| task | RPF-WP-0064-T04 | todo | — | workplans/RPF-WP-0064-isolated-original-openbao-restore.md |
|
||||
| task | RPF-WP-0064-T05 | wait | — | workplans/RPF-WP-0064-isolated-original-openbao-restore.md |
|
||||
| task | RPF-WP-0064-T06 | wait | — | workplans/RPF-WP-0064-isolated-original-openbao-restore.md |
|
||||
| task | RPF-WP-0064-T07 | wait | — | workplans/RPF-WP-0064-isolated-original-openbao-restore.md |
|
||||
| task | RPF-WP-0064-T08 | wait | — | workplans/RPF-WP-0064-isolated-original-openbao-restore.md |
|
||||
| intake | RPF-IN-0001 | closed | — | intakes/intakes.md |
|
||||
| intake | RPF-IN-0002 | open | — | intakes/intakes.md |
|
||||
| intake | RPF-IN-0003 | open | — | intakes/intakes.md |
|
||||
|
|
|
|||
262
workplans/RPF-WP-0064-isolated-original-openbao-restore.md
Normal file
262
workplans/RPF-WP-0064-isolated-original-openbao-restore.md
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
---
|
||||
id: RPF-WP-0064
|
||||
type: workplan
|
||||
title: "Isolated original-OpenBao restore for secrets-engine consumer continuity"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: proposed
|
||||
flavor: implementation
|
||||
owner: claude
|
||||
created: "2026-10-23"
|
||||
updated: "2026-10-23"
|
||||
related:
|
||||
- SECRETS-WP-0015
|
||||
- NK-WP-0049
|
||||
- RPF-WP-0015
|
||||
- RPF-WP-0036
|
||||
- RPF-WP-0035
|
||||
- RAPP-OPENBAO-WP-0001
|
||||
---
|
||||
|
||||
# RPF-WP-0064 — Isolated original-OpenBao restore for secrets-engine consumer continuity
|
||||
|
||||
Receiving workplan for hub message `41e9af3e` from net-kingdom (case
|
||||
`secrets15-nk49-readiness`). The founder accepted on 2026-10-23 that
|
||||
railiance-platform owns this as source preparation.
|
||||
|
||||
NK-WP-0049-T18 (net-kingdom `a09bf20`, verified receipt sha256 `16d72f7c…1651`,
|
||||
secrets-engine `bfa1b3b`) proved in isolation that the original KeyCape issuer, its
|
||||
JWKS key and the archived `secrets-engine-openbao` registration are intact.
|
||||
SECRETS-WP-0015-T04 also needs the original OpenBao, recovered on its own into an
|
||||
isolated, network-contained target. That recovery uses the original custody and
|
||||
unseal path. It must show the KV registration
|
||||
`platform/workloads/keycape/secrets-engine-openbao`, the narrow secrets-engine
|
||||
JWT role and the operator auth path. There is no production redirect, no fresh
|
||||
backend standing in for the original and no injected secret.
|
||||
|
||||
Scope of this plan: the restore and its evidence only. The secrets-engine
|
||||
consumer run (attended in-memory secret source, KeyCape exchange, OpenBao JWT
|
||||
login, `openbao:admin` refusal, session revocation) is a separate
|
||||
founder-admitted attempt owned by secrets-engine. This plan prepares its target.
|
||||
|
||||
Why not RPF-WP-0036-T03: that task owns *recurring* backup/restore assurance and
|
||||
waits on the activity-core scheduler (ACTIVITY-WP-0042). This is a one-off
|
||||
attended restore with no scheduler, so a separate plan avoids taking on that
|
||||
dependency. Its evidence can later feed T03 as one isolated restore receipt.
|
||||
RPF-WP-0015 keeps the live snapshot experiments. Its snapshot receipts authorize
|
||||
no restore.
|
||||
|
||||
Nothing in this plan claims restore capability or consumer continuity. Every
|
||||
live step stays `wait` until attended evidence exists.
|
||||
|
||||
## T01 — Source survey and recorded findings
|
||||
|
||||
```task
|
||||
id: RPF-WP-0064-T01
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
### Findings (2026-10-23, read-only source survey; no cluster, OpenBao or snapshot access)
|
||||
|
||||
1. **Snapshot capture and location.** The procedure is `docs/openbao.md` §Backup:
|
||||
`bao operator raft snapshot save` on `openbao-0`, then age encryption before the
|
||||
snapshot leaves the operator machine. The latest recorded capture is the
|
||||
attended RPF-WP-0015-T03 hold point on 2026-10-14. That snapshot was encrypted
|
||||
to the offsite recipient derived from the founder's offline
|
||||
`railiance-backup.key`, decrypt-verified in memory and uploaded to
|
||||
`railiance-backups/openbao/` (HTTP 201), and the plaintext was shredded from
|
||||
tmpfs. An earlier 2026-08-23 drill receipt is at
|
||||
`reviews/WARDEN-WP-0027-T02-DRILL-20260822-01-openbao-snapshot-receipt.json`.
|
||||
Receipts are validated against `docs/openbao-reboot-snapshot-receipt.example.json`
|
||||
(24 h freshness, cluster id, applied index). Those receipts authorize no
|
||||
restore.
|
||||
2. **Freshness against the needed objects.** The KV path was corrected to
|
||||
`platform/workloads/keycape/secrets-engine-openbao` on 2026-10-06, and the JWT
|
||||
role was proven live on 2026-10-10 (CCR-2026-0038). The 2026-10-14 snapshot
|
||||
should therefore contain both. This is an inference until the restored
|
||||
metadata readback confirms it. If they are missing, T07 stops; it does not
|
||||
repair anything.
|
||||
3. **Version pin.** Chart `openbao/openbao` `0.28.2` (`Makefile`
|
||||
`OPENBAO_CHART_VERSION`); image `quay.io/openbao/openbao:2.5.4`
|
||||
(`helm/openbao-values.yaml`; `docs/openbao.md` still says app `v2.5.3`, which
|
||||
is stale doc text). The restore target must use the same image, pinned by
|
||||
digest at rehearsal time. Storage is integrated Raft.
|
||||
4. **Unseal and custody model in use.** Shamir 2-of-3, unsealed by the founder in
|
||||
attendance (the 2026-10-14 post-reboot unseal was done outside the transcript).
|
||||
The transit auto-unseal stanza is still commented out. A Raft snapshot restore
|
||||
brings back the *original* barrier keyring, so the restored target unseals only
|
||||
with the original shares. That is the "original unseal path" the request asks
|
||||
for. Restoring needs a throwaway initialization of the empty target first. Its
|
||||
throwaway keys and token stay in process memory, are never recorded, and stop
|
||||
working once `snapshot restore -force` completes. This is not a "fresh backend"
|
||||
in the request's sense, because no state from it survives.
|
||||
5. **Role, KV and auth definitions are owned here, not in rapp-openbao.** The
|
||||
sources are `openbao/auth/secrets-engine-jwt-role.json`,
|
||||
`openbao/auth/keycape-services-config.json` (mount `keycape-services`),
|
||||
`docs/contracts/secrets-engine-openbao-jwt-login.yaml`, the operator path
|
||||
`openbao/auth/netkingdom-oidc-config.json` plus
|
||||
`netkingdom-platform-admin-role.json` (mount `netkingdom`, role
|
||||
`platform-admin`), and the workload KV lane (`docs/workload-kv-access-lanes.md`,
|
||||
KeyCape provisioning window 2026-10-04). rapp-openbao's SCOPE excludes policy,
|
||||
custody and workload KV lanes. It owns only the package (chart, values, UI
|
||||
overlay), and neither of its workplans has a restore task. rapp-openbao only
|
||||
needs to confirm the image/chart pin used by the target.
|
||||
6. **Isolation constraint found.** `keycape-services` validates JWTs through
|
||||
`jwks_url: https://kc.coulomb.social/jwks`, and `netkingdom` uses OIDC
|
||||
discovery at `https://kc.coulomb.social`. A networkless OpenBao can restore,
|
||||
unseal and read back configuration and metadata. However, a live JWT login
|
||||
(the consumer run) needs that hostname to resolve inside the contained network
|
||||
to the *isolated* NK49 KeyCape, with a trusted TLS chain. It must never reach
|
||||
the production KeyCape. An interactive OIDC operator login is out of scope for
|
||||
the isolated target. The operator path is proven by restored config and role
|
||||
readback, plus root-less login refusal where applicable.
|
||||
7. **Reusable patterns.** These are reused as patterns, not copied:
|
||||
- Existing in-repo template `docs/openbao-restore-drill-evidence.example.json`
|
||||
and its validator `make openbao-validate-restore-evidence`.
|
||||
- net-kingdom `docs/bootstrap-recovery-ceremony.md` and
|
||||
`tools/bootstrap-recovery/isolated-*.py`: attended, hidden-key, fail-closed
|
||||
setup with a Docker `--network none` target, a safe receipt and an
|
||||
independent verifier.
|
||||
- secrets-engine `docs/founder-admission.md` for the founder SSH-signed
|
||||
admission with a time window.
|
||||
|
||||
## T02 — Isolated target and adapter design
|
||||
|
||||
```task
|
||||
id: RPF-WP-0064-T02
|
||||
status: todo
|
||||
priority: high
|
||||
depends_on: [RPF-WP-0064-T01]
|
||||
```
|
||||
|
||||
Design `scripts/openbao-isolated-restore/` (adapter plus doc). Fixed properties:
|
||||
|
||||
- **Target:** a disposable Docker container on the founder workstation, running
|
||||
the T01 image digest with an in-container Raft data directory on tmpfs. It is
|
||||
never on railiance01 or the cluster, and it has no kubeconfig, no host
|
||||
networking and no published ports.
|
||||
- **Network containment:** phase A (restore + readback) uses `--network none`.
|
||||
Phase B (handed to the consumer run) uses a single `--internal` Docker network
|
||||
that has only the isolated KeyCape from NK49 and this OpenBao. In phase B,
|
||||
`kc.coulomb.social` resolves to the isolated KeyCape, and egress is checked
|
||||
to be refused before admission. Phase B is offered, not run, by this plan.
|
||||
- **Custody inputs**, all founder-attended and never through argv, files in the
|
||||
repo, env dumps or logs:
|
||||
- (a) the encrypted snapshot object from `railiance-backups/openbao/`, named by
|
||||
its ciphertext sha256;
|
||||
- (b) the offline `railiance-backup.key` age identity, used for decryption
|
||||
straight into the tmpfs stream;
|
||||
- (c) 2 of 3 original Shamir shares, entered through a hidden prompt.
|
||||
The restore needs no root token and no secret value is read. Readback uses a
|
||||
token created in the restored target by an attended `generate-root`, used in
|
||||
memory only and revoked before teardown, or uses the restored operator path.
|
||||
Which of the two is decided in T02 review.
|
||||
- **Readback (metadata only):** `sys/seal-status`, Raft applied index and cluster
|
||||
id; the mounts `keycape-services` and `netkingdom` and their configs (issuer
|
||||
and JWKS URL); role `secrets-engine-openbao` (bound claims and policies compared
|
||||
to the source JSON hash); `platform/workloads/keycape/secrets-engine-openbao`
|
||||
KV **metadata** (versions and timestamps, never `data`); and policy names. No
|
||||
KV `data` read.
|
||||
- **Timeout/abort/cleanup:** a hard wall-clock limit of 45 minutes from the first
|
||||
custody input. Any fail-closed check, a missing object, an unexpected network
|
||||
interface, or the founder pressing abort leads to `docker rm -f`, tmpfs
|
||||
unmount, shredding of the decrypted stream, and a recorded `aborted` receipt.
|
||||
Teardown also runs on success, unless phase B was admitted in the same window.
|
||||
The plaintext snapshot never touches persistent disk.
|
||||
|
||||
## T03 — Safe receipt schema and independent verifier
|
||||
|
||||
```task
|
||||
id: RPF-WP-0064-T03
|
||||
status: todo
|
||||
priority: high
|
||||
depends_on: [RPF-WP-0064-T02]
|
||||
```
|
||||
|
||||
Extend `docs/openbao-restore-drill-evidence.example.json` into a v2 receipt:
|
||||
- attempt id and admission hash;
|
||||
- image digest;
|
||||
- ciphertext sha256 of the snapshot and the source cluster id and applied index
|
||||
(from the RPF-WP-0015 receipt);
|
||||
- restored cluster id and index;
|
||||
- a network-namespace proof (interfaces and the egress-refusal result);
|
||||
- presence and source-hash match for each required object;
|
||||
- result `restored | refused | aborted`;
|
||||
- the teardown proof;
|
||||
- `no_secret_material_recorded`.
|
||||
|
||||
Add a verifier that runs separately from the adapter. It rejects placeholders,
|
||||
unknown fields, missing teardown, `data` fields, and anything shaped like a
|
||||
token or share. Validate it with adversarial fixtures.
|
||||
|
||||
## T04 — Staged rehearsal with synthetic material
|
||||
|
||||
```task
|
||||
id: RPF-WP-0064-T04
|
||||
status: todo
|
||||
priority: high
|
||||
depends_on: [RPF-WP-0064-T03]
|
||||
```
|
||||
|
||||
Run the full adapter against a synthetic OpenBao, initialized on purpose with
|
||||
generated Shamir shares and seeded with stand-in mounts, role and KV metadata
|
||||
that mirror the T01 source files. Snapshot it, age-encrypt it to a generated
|
||||
identity, restore it into the T02 target, unseal it with the synthetic shares,
|
||||
read it back, and tear it down. Rehearse each abort path (timeout, wrong
|
||||
ciphertext hash, network interface present, missing object). This step uses no
|
||||
real material.
|
||||
|
||||
## T05 — Founder-signed attempt admission
|
||||
|
||||
```task
|
||||
id: RPF-WP-0064-T05
|
||||
status: wait
|
||||
priority: high
|
||||
needs_human: true
|
||||
depends_on: [RPF-WP-0064-T04]
|
||||
blocking_reason: "Founder must sign (SSH, secrets-engine founder-admission pattern) an attempt admission naming the snapshot ciphertext sha256, image digest, adapter commit, window start/end, abort operator and phase A only (phase B separately). Needs T04 rehearsal receipt first."
|
||||
```
|
||||
|
||||
## T06 — Owner confirmation of package pin
|
||||
|
||||
```task
|
||||
id: RPF-WP-0064-T06
|
||||
status: wait
|
||||
priority: low
|
||||
depends_on: [RPF-WP-0064-T02]
|
||||
blocking_reason: "rapp-openbao confirms the chart 0.28.2 / image 2.5.4 pin (and digest) used by production at the 2026-10-14 snapshot time is the one the isolated target runs. Role/KV/auth definitions stay railiance-platform-owned; no rapp-openbao change requested."
|
||||
```
|
||||
|
||||
## T07 — Attended original restore (phase A)
|
||||
|
||||
```task
|
||||
id: RPF-WP-0064-T07
|
||||
status: wait
|
||||
priority: high
|
||||
needs_human: true
|
||||
depends_on: [RPF-WP-0064-T05, RPF-WP-0064-T06]
|
||||
blocking_reason: "Requires the founder in attendance holding the offline railiance-backup.key, 2 of 3 original Shamir shares and the encrypted snapshot from railiance-backups/openbao/, inside the T05-signed window. No agent handles custody material."
|
||||
```
|
||||
|
||||
Run the admitted adapter once. The outcome is a T03 receipt verified
|
||||
independently. The receipt is kept outside Git and referenced by its hash. A
|
||||
missing object or failed check is a valid `refused` outcome; it is not repaired
|
||||
in this attempt.
|
||||
|
||||
## T08 — Bounded evidence handoff
|
||||
|
||||
```task
|
||||
id: RPF-WP-0064-T08
|
||||
status: wait
|
||||
priority: medium
|
||||
depends_on: [RPF-WP-0064-T07]
|
||||
blocking_reason: "Needs the verified T07 receipt."
|
||||
```
|
||||
|
||||
Hand to secrets-engine (SECRETS-WP-0015-T04) and net-kingdom (NK-WP-0049-T18)
|
||||
the receipt hash, the verifier result, the image digest and the recovered-object
|
||||
list. Also hand over the phase B offer terms (contained network with the
|
||||
isolated KeyCape, same custody, its own admission). The handoff makes no
|
||||
continuity claim. A pointer to the receipt goes to RPF-WP-0036-T03 as one
|
||||
isolated restore receipt; it does not count as recurring assurance.
|
||||
Loading…
Add table
Add a link
Reference in a new issue