diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index bb05bce..39a4fa7 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -45,6 +45,7 @@ | workplan | RPF-WP-0063 | finished | — | workplans/RPF-WP-0063-wave2-resource-right-sizing.md | | workplan | RPF-WP-0064 | active | — | workplans/RPF-WP-0064-isolated-original-openbao-restore.md | | workplan | RPF-WP-0065 | proposed | — | workplans/RPF-WP-0065-netkingdom-role-claim-bindings.md | +| workplan | RPF-WP-0066 | proposed | — | workplans/RPF-WP-0066-openbao-durable-audit-snapshots-conformance.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 | @@ -208,6 +209,12 @@ | task | RPF-WP-0065-T03 | done | — | workplans/RPF-WP-0065-netkingdom-role-claim-bindings.md | | task | RPF-WP-0065-T04 | wait | — | workplans/RPF-WP-0065-netkingdom-role-claim-bindings.md | | task | RPF-WP-0065-T05 | wait | — | workplans/RPF-WP-0065-netkingdom-role-claim-bindings.md | +| task | RPF-WP-0066-T01 | todo | — | workplans/RPF-WP-0066-openbao-durable-audit-snapshots-conformance.md | +| task | RPF-WP-0066-T02 | wait | — | workplans/RPF-WP-0066-openbao-durable-audit-snapshots-conformance.md | +| task | RPF-WP-0066-T03 | todo | — | workplans/RPF-WP-0066-openbao-durable-audit-snapshots-conformance.md | +| task | RPF-WP-0066-T04 | wait | — | workplans/RPF-WP-0066-openbao-durable-audit-snapshots-conformance.md | +| task | RPF-WP-0066-T05 | wait | — | workplans/RPF-WP-0066-openbao-durable-audit-snapshots-conformance.md | +| task | RPF-WP-0066-T06 | todo | — | workplans/RPF-WP-0066-openbao-durable-audit-snapshots-conformance.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 | diff --git a/workplans/RPF-WP-0036-platform-service-assurance.md b/workplans/RPF-WP-0036-platform-service-assurance.md index a974ef3..aa231a3 100644 --- a/workplans/RPF-WP-0036-platform-service-assurance.md +++ b/workplans/RPF-WP-0036-platform-service-assurance.md @@ -71,6 +71,9 @@ priority: high state_hub_task_id: "d64446fb-870b-5ae9-9628-f1fb9d06c5a4" ``` +2026-10-27: the OpenBao Raft snapshot schedule slice is tracked as RPF-WP-0066-T05 +for NetKingdom NK-WP-0055; this task keeps the cross-service scope. + 2026-10-11: requalified after founder decision D2 (ArgoCD owns production) resolved — see the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md. 2026-10-11 dependency audit: D2 resolved the scheduling-role decision. The diff --git a/workplans/RPF-WP-0066-openbao-durable-audit-snapshots-conformance.md b/workplans/RPF-WP-0066-openbao-durable-audit-snapshots-conformance.md new file mode 100644 index 0000000..b65eeb6 --- /dev/null +++ b/workplans/RPF-WP-0066-openbao-durable-audit-snapshots-conformance.md @@ -0,0 +1,194 @@ +--- +id: RPF-WP-0066 +type: workplan +title: "OpenBao durable audit shipping, scheduled Raft snapshots and live conformance receipt" +domain: financials +repo: railiance-platform +status: proposed +flavor: implementation +owner: claude +created: "2026-10-27" +updated: "2026-10-27" +related: + - NK-WP-0055 + - RPF-WP-0036 + - RPF-WP-0064 + - AUDIT-WP-0013 + - AUDIT-WP-0015 + - ACTIVITY-WP-0042 +--- + +# RPF-WP-0066 — OpenBao durable audit, scheduled snapshots, live conformance + +Receiving workplan for NetKingdom NK-WP-0055-T11 (audit sink) and the OpenBao part of +NK-WP-0055-T12 (live conformance receipts). Source: net-kingdom +`docs/evidence/2026-10-27-production-readiness-ledger.md` sections 4 (OpenBao) and 9 +(Audit sink). + +## Evidence + +- The declarative `audit "file" "file"` stanza in `helm/openbao-values.yaml` writes + `/openbao/audit/openbao-audit.log` on the audit PVC. `docs/openbao.md` states the PVC + "is not a durable audit sink". Durable shipping was deferred when RAIL-PL-WP-0002 + closed, and no live workplan owned it until now. +- `make openbao-reboot-snapshot` is an attended Raft snapshot -> age -> verify -> offsite + path with a receipt. RPF-WP-0064-T07/T08 proved one isolated original restore. Neither + is a schedule. RPF-WP-0036-T03 owns recurring backup and restore evidence for all S3 + data services and waits on ACTIVITY-WP-0042 (bounded scheduler). +- `make openbao-verify-authenticated` already runs non-mutating checks of audit devices, + `platform/`, and the `kubernetes/`, `netkingdom/`, `keycape/` auth mounts. It does not + compare the live state to `openbao/policies/` and does not write a dated receipt. + +## Constraints + +- Source preparation only. Every live step (Helm rollout, enabling an audit device, + installing a schedule, the drills) is founder-run, with a guarded helper and the exact + command, and keeps its own execution gate. +- Audit records leave OpenBao with its default HMAC-SHA256 hashing of secret-bearing + request and response fields. No `log_raw`, and no `hmac_accessor=false`. Any + `audit_non_hmac_*_keys` tuning on a mount needs a separate reviewed change. The shipper + never logs record bodies and never holds an OpenBao token. +- OpenBao blocks requests when every enabled audit device fails. The file device stays + enabled as the local, blocking device. Shipping must be asynchronous, so a sink + outage cannot stop OpenBao. + +## Choose the OpenBao audit forwarding design + +```task +id: RPF-WP-0066-T01 +status: todo +priority: high +``` + +Compare the options and record the decision in `docs/openbao.md` (or an ADR if it +changes the platform boundary): + +1. **File device plus a tailing sidecar shipper (preferred candidate).** A shipper such as + Vector or Fluent Bit in the `openbao` pod reads the PVC log, keeps a disk checkpoint, + maps records to the audit-core envelope and posts them to the audit-core ingest API + as a registered sender. It retries with backoff from the PVC backlog. The PVC is the + buffer; size it and set a rotation that cannot drop unshipped lines. Rotation would + use SIGHUP to reopen the log. +2. **Socket device to an in-cluster collector.** This has lower latency, but a socket + failure counts against the "all devices failed" rule. It is acceptable only as a + second, non-sole device, and its `fallback` semantics need checking. +3. **Separate durable store** (an encrypted object store with object lock). Use this only + if audit-core cannot accept OpenBao volume. It then needs its own retention and its + own restore drill. + +**Done when:** one option is chosen with volume and backlog sizing, and its failure modes +are recorded: sink down, shipper down, PVC full, rotation. + +## Agree the audit-core sender contract and the correlation id + +```task +id: RPF-WP-0066-T02 +status: wait +priority: high +blocked_on: message-from:audit-core +``` + +Needed from audit-core (AUDIT-WP-0013 sender admission): + +- an OpenBao sender registration and its credential route (OpenBao-issued, no secret + in Git); +- an envelope mapping for OpenBao `request`/`response` records, with HMAC'd fields + passed as opaque; +- idempotency and dedup keys (OpenBao `request.id` plus record type); +- the expected volume and retention class; +- an acknowledgement and backpressure contract. + +Correlation: the NetKingdom-owned cross-stream correlation id (NK-WP-0055-T11) has to +reach OpenBao requests. Set a request header such as `X-Correlation-Id`. If the +listener allows it, record it through the auth mount `audit_non_hmac_request_keys` / +`passthrough_request_headers` or the listener header settings. Otherwise derive it from +the OIDC `jti`/session claim in entity metadata. Verify which of these OpenBao records +unhashed without exposing a secret. + +**Done when:** a written contract exists in both repos, and NetKingdom's correlation-id +definition is cited. + +## Implement the shipper source and its tests + +```task +id: RPF-WP-0066-T03 +status: todo +priority: high +depends_on: [RPF-WP-0066-T01, RPF-WP-0066-T02] +``` + +Add the shipper configuration to `helm/openbao-values.yaml`, along with the checkpoint +volume, log rotation, and the mapping and redaction config. Test against synthetic +fixtures: + +- records stay HMAC'd end to end; +- no token or accessor appears in the clear; +- dedup holds on replay; +- the backlog drains after a simulated sink outage; +- correlation-id propagation works. + +Prepare a founder-run rollout helper with a post-rollout check: the audit-core record +count rises for a probe request carrying a known correlation id. + +**Done when:** tests pass and the helper and its exact command are documented. The live +rollout is a separate attended step. + +## Set retention and drill audit restore + +```task +id: RPF-WP-0066-T04 +status: wait +priority: medium +depends_on: [RPF-WP-0066-T03] +``` + +Record retention per store: the PVC (short, buffer only), audit-core (its retention +class), and any separate archive. The recurring audit-core restore drill belongs to +audit-core (NK-WP-0055-T11 / AUDIT-WP-0015-T01). This task supplies the OpenBao part: +after a restore, an OpenBao record found by correlation id and `request.id` verifies +against the hash chain. If option 3 is chosen in T01, this repo owns the full restore +drill of that store. + +**Done when:** a dated restore receipt shows OpenBao records recovered and verified. + +## Schedule OpenBao Raft snapshots + +```task +id: RPF-WP-0066-T05 +status: wait +priority: high +depends_on: [RPF-WP-0036-T03, ACTIVITY-WP-0042] +``` + +This is the OpenBao slice of RPF-WP-0036-T03, split out so NK-WP-0055 can track it. +Turn `scripts/openbao-reboot-snapshot.py` (snapshot -> age -> verify -> offsite -> +receipt) into an unattended, bounded operation run by the accepted scheduler +(ACTIVITY-WP-0042). It needs: + +- a snapshot-only OpenBao policy, `sys/storage/raft/snapshot` read and nothing more; +- a scoped credential route; +- a cadence and expiry that RPF-WP-0036-T02's freshness signal can check; +- a stale or failed run that reaches a named operator. + +A periodic isolated restore, reusing the RPF-WP-0064 isolated-restore path, is the +recurring proof. A dated snapshot alone does not pass. + +**Done when:** the schedule is installed through the execution owner, and at least two +consecutive scheduled snapshot receipts and one scheduled isolated restore receipt exist. + +## Record a dated live check of auth methods and mounts against committed policies + +```task +id: RPF-WP-0066-T06 +status: todo +priority: medium +``` + +Extend `make openbao-verify-authenticated`, or add a sibling read-only target, to emit a +dated, non-secret receipt. The receipt diffs `bao auth list`, `bao secrets list`, +`bao audit list` and `bao policy list`, plus per-policy content hashes, against +`openbao/policies/*.hcl` and the expected mounts list. It lists unexpected mounts, +missing mounts and policy drift. The founder runs it; the receipt is committed under +`docs/evidence/`. + +**Done when:** one dated receipt is committed and cited in NK-WP-0055-T12.