railiance-platform/openbao/root-grant/README.md
codex 2151879c68
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
docs(custody): close producer delivery with verified provider recovery
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a1029d-2c93-7500-a0e0-e3e089668b29
2026-10-03 21:59:29 +02:00

264 lines
16 KiB
Markdown

# Approved platform-root producer design
Prepared for NK-WP-0045-T05 / RPF-WP-0049, 2026-10-03. Founder approved:
"Accept ADR-0017 and approve the proposed OpenBao delivery design."
Scoped made decision receipt: `c2cff929-91b9-4018-bfd6-fa04f7da8280`.
This selects railiance-platform and the exact source below. Identity admission,
attended live provisioning, custody provenance and live readiness remain pending.
NetKingdom canon remains authoritative; reviewed baseline is net-kingdom commit
`db319335b27b61b855382ee5af5d690f06eeb010`. Deployments must pin the validator
and its schema together, and reconcile amendments before publication.
## Approved source and transport
- KV v2 mount: `platform` (existing owner convention; live suitability unverified).
- Exact API path: `/v1/platform/data/custody/net-kingdom/platform-root`.
- `record_id`: `nk-custody:platform-root`; `owner_system`: `net-kingdom-custody`.
- API response unwrap: `data.data.document` is the complete canon document.
`data.metadata.version` is KV concurrency state, distinct from canon revision.
- Reader: owner manifests identify namespace `user-engine`, ServiceAccount
`user-engine`. Role `user-engine-root-custody-reader` on `auth/kubernetes`
binds exactly those values and audience `openbao`. Tokens last at most 60s,
with no default policy. Dedicated projected JWT is owned by rapp-user-engine;
the existing flex-auth JWT and ESO AppRole are not reused. Live admission
remains unexecuted. Reader policy is exact-path read;
no list, sibling read or write. Never distribute an attended writer token.
- Writer: separate human custody lane, bounded attended MFA operator login,
reviewed exact-path policy. This packet does not grant a credential or role.
- Reader timeout 5 seconds, maximum document 256 KiB. A successful authenticated
owner read, not document time or a cache read, sets observed_at. Failure means
no grant. No raw server response/error logging.
## Offline implementation
`scripts/root_grant_publish.py` creates a single KV v2 CAS payload from a
candidate, previous document, exact previous KV version and the pinned
NetKingdom validator module. No network or publication is implemented here.
It validates both documents, exact source identity and successor semantics;
refuses missing existing baselines, same-revision changes and rollback. CAS=0
is bootstrap-only, CAS=current-version updates; a CAS conflict requires a fresh
owner read and revalidation, never blind retry. It never prints documents.
The attended executor is implemented in `scripts/root_grant_attended.py`:
- `provision` checks existing Kubernetes auth and active audit, admits only the
exact reviewed reader policy/role, enables CAS on this key and verifies all
readbacks. Differing existing policies/roles are refused without overwrite.
- `publish` reads current document and KV version together, validates pinned
canon and the persisted high-water baseline, fsyncs a pending journal before
CAS write, verifies exact readback, retains immutable local history and
atomically advances state. Exact replay creates no new version. Ambiguous
writes recover only after exact matching owner readback and durable history.
- `restore-check` requires the independently retained publisher baseline to
match the restored source exactly. Missing/different baseline never resets
authority or permits rollback. Off-host history backup is still an execution
dependency; local files alone cannot prove safe disaster restoration.
- The silent child requires the existing warden attended-login envelope and
exact loopback OpenBao tunnel. No raw process response/error is emitted.
Every invocation requires a new receipt path: old success receipts are refused.
## Authorized attended execution packet
Founder approval to "go forward" authorizes continued implementation and bounded
provisioning of the approved design. No additional generic design approval is
requested. Attended OIDC/MFA must still run in the founder's own terminal:
```bash
BAO_ADDR=http://127.0.0.1:18200 VAULT_ADDR=http://127.0.0.1:18200 \
warden access openbao-platform-admin-login --exec -- \
/home/worsch/railiance-platform/scripts/root-grant-attended.sh provision \
--receipt /tmp/platform-root-admission-UNIQUE-RUN.json
```
Replace UNIQUE-RUN with a fresh run identifier. The child is silent. Inspect the
new JSON receipt and warden's printed result; a shell exit code or previous
receipt cannot establish success. Provisioning does not create a custody grant.
Existing operator platform-admin identity provides the human writer lane;
this packet does not create another privileged identity or reuse its token in
user-engine. Deployment/network policy/consumer activation belongs to
rapp-user-engine and follows source image publication and admission receipts.
The founder reported that no actual custody ceremony is known. NetKingdom has
therefore prepared `examples/custody-record/initial-empty-record.json`, a
schema-valid first publication candidate with `entries: []`. It establishes no
root grant. The non-secret provenance is
`net-kingdom/docs/evidence/2026-10-03-root-grant-delivery-progress.md`.
Continued go-forward approval covers preparing and publishing this no-grant
baseline through the attended owner lane; no new generic approval is needed.
A future real grant still requires a genuine signed human ceremony with exact
issuer and subject; planned roster/LLDAP membership cannot supply it.
After successful admission, run this second attended step in the founder's
terminal. Create the operator-owned state directory first; it must persist
outside the checkout and outside warden's temporary attended-login home.
```bash
install -d -m 700 /home/worsch/.local/state/net-kingdom-root-custody
BAO_ADDR=http://127.0.0.1:18200 VAULT_ADDR=http://127.0.0.1:18200 \
warden access openbao-platform-admin-login --exec -- \
/home/worsch/railiance-platform/scripts/root-grant-attended.sh publish \
--candidate /home/worsch/net-kingdom/examples/custody-record/initial-empty-record.json \
--state /home/worsch/.local/state/net-kingdom-root-custody/baseline.json \
--provenance-ref net-kingdom/docs/evidence/2026-10-03-root-grant-delivery-progress.md \
--net-kingdom /home/worsch/net-kingdom \
--validator-digest 9156e399c8d92a45b817bfc3738c89843487ce57e1718ed747f804f95cc719bb \
--schema-digest bb6cd6da5dc48eddcf118ae78c2cacfafd5f860098fd8a8368fe6bc845776d07 \
--receipt /tmp/platform-root-publish-UNIQUE-RUN.json
```
Inspect the new receipt. Existing source without independently retained state
is refused rather than overwritten; a failed/ambiguous write requires owner
readback and journal recovery. Bootstrap uses CAS=0. The publisher retains
baseline.json and immutable history/ receipts. Restore `baseline.json`, history/
and any pending journal from independently retained latest evidence before a
recovery check; restoring only an older OpenBao snapshot cannot establish
current authority. The operator-workstation state is already off-host and independent of
railiance01/OpenBao. Documenting backup and readback of that receipt holder
remains an explicit acceptance dependency; no new service is required merely
to duplicate it. Local state enables safe
publication but does not satisfy that independent recovery proof.
`restore-check` takes the same source pins and state but no candidate or
provenance argument, plus a fresh receipt path, via the same attended wrapper.
Source digests enforce the reviewed NetKingdom validator and schema without
importing an unreviewed path. Neither command should print document contents,
privileged tokens or raw backend errors.
Acceptance also needs revocation/supersession exercise and rollback/restore
receipts. Exercise real grant changes only under their own custody ceremony
approval. Use isolated synthetic paths for non-live algorithm exercises.
## History, recovery and audit
OpenBao audit is owned by railiance-platform; the custody fact and ceremony are
owned by net-kingdom-custody. Confirm mount backup owner and restoration before
calling this source live. Retain KV history and independent publication digest /
revision high-water receipts. Readers persist their own trusted baseline across
restart. A restored snapshot must not reactivate an older grant: suspend reads,
compare restored record with independently retained latest baseline, reconcile
all later custody actions, and re-enable only after owner receipts. Do not
reset baselines, destroy versions or recreate an old record under the same ID.
KV CAS prevents races, but is not proof against snapshot rollback. Retention and workstation receipt-holder backup/readback proof remain owner
acceptance requirements, alongside isolated OpenBao recovery evidence.
No control was relaxed and no live action was taken. Emergent knowledge 0.2.3
start was withheld/orientation-only (digest
60f8811c6b94b30d357a0d9e5022f2a8ea52e69b47138d3a536755f3295310b5);
source review read the-custodian agent-environment-orientation section 0 and
informed-decision README, plus the source NetKingdom contract/schema/validator.
Producer delivery receipts complete RPF-WP-0049-T05 / NK-WP-0045-T05.
Consumer integration and runtime acceptance follow in USER-WP-0037-T02 /
NK-WP-0045-T06; they do not block initial producer delivery.
## Attended execution outcome — 2026-10-03
The founder executed admission and empty publication. Fresh receipts, initial
revision 1/KV1/no-grant digest and exact residual recovery/reader evidence are
recorded in [delivery evidence](../../docs/evidence/2026-10-03-platform-root-custody-delivery.md).
This completes RPF-WP-0049-T04. T05 remains evidence-blocked; generic approval
is not pending. Old operator role configuration is not an execution receipt.
## Remaining bounded attended finish
Native isolated Raft recovery and local receipt-holder scratch restoration now
pass. The operator-owned directory has no discovered workstation backup job.
The non-authoritative recovery copy in docs/evidence/root-custody-history enters
the existing owner Forgejo source backup scope; that does not imply a fresh
provider archive has included this new commit. One attended command completes
current live baseline check plus direct protected history provider readback:
```bash
BAO_ADDR=http://127.0.0.1:18200 VAULT_ADDR=http://127.0.0.1:18200 \
warden access openbao-platform-admin-login --exec -- \
/home/worsch/railiance-platform/scripts/root-custody-finish-attended.sh \
--state /home/worsch/.local/state/net-kingdom-root-custody/baseline.json \
--net-kingdom /home/worsch/net-kingdom \
--receipt /tmp/platform-root-finish-UNIQUE-RUN.json
```
The silent child uses the current governed OpenBao backup account/lane only,
requires the known Backup owner and create-only share shape, checks quota,
encrypts history with current escrow, creates one uniquely named artifact under
the existing forgejo/ backup folder, downloads through operator authority and
verifies ciphertext and decrypted history equality. It deletes nothing and
changes no credential or policy. Read the fresh receipt; old receipts are refused.
A local historical rclone configuration was found during backup discovery and
its credential-bearing coordinates may have appeared in tool output. It is
never reused. The helper compares that share with the current lane in memory
and records only booleans. If it is the current lane, the helper stops before
upload and requires coordinated existing credential incident/cutover recovery,
preserving consumers; it never rotates an uninformed predecessor. If different,
the historical owner's revocation status remains unverified separately from
root-grant authority. No credential-bearing coordinates are copied to evidence.
## Finish failure receipts
The first finish attempt failed after successful authenticated owner reads but
before a receipt. Its exact provider cause was lost by the old catch-all; it is
not evidence of missing IAM. The corrected wrapper reserves a fresh receipt
before helper imports and always records safe stage/error codes. Inspect that
receipt after execution even if the child returns nonzero. Failed upload or
readback includes safe numeric HTTP status and generated artifact name when
available; do not rerun with the same receipt path or weaken expected provider
contract/status checks blindly. No token, share coordinates, private key, raw
response or exception message is written. `helper_import` means startup failed;
`backup_operator_read` means current owner credential retrieval failed;
`provider_contract`, crypto, quota, upload/download or ciphertext/decrypt stages
identify the remaining provider proof boundary. Login cleanup and task success
remain separate, and only a verified fresh success receipt completes T05.
The finish helper also uses the established independent operator escrow at
/home/worsch/.config/age/railiance-backup.key. It derives that key's public
recipient in a captured subprocess, compares it with the current governed lane
and decrypts the downloaded artifact with the independent key file. Only match
and decryption booleans are recorded; the private key is never read into logs
or replaced. A missing/different escrow is an explicit fixed-code recovery
failure, not a request to create or reset a key implicitly.
The 2026-10-03 finish receipt returned HTTP401 at public upload after current
baseline and independent escrow verification passed. Corrected clients include
Nextcloud's required `X-Requested-With: XMLHttpRequest` header for public DAV
non-GET operations. See [official DAV documentation](https://docs.nextcloud.com/server/stable/developer_manual/client_apis/WebDAV/basic.html)
and [stable31 public handler](https://github.com/nextcloud/server/blob/stable31/apps/dav/appinfo/v2/publicremote.php).
Live causality is unproved until a fresh attended finish run succeeds. This
changes request protocol only; preserve lane/token/permissions and do not rotate
credentials or fall back to wider account uploads. Failure receipts now retain
current lane KV version. The historical exposed share differs from current
lane; separate historical owner/revocation evidence remains unverified.
The corrected-header retry still returned401 against lane KVversion3. Before
another upload use the same attended wrapper with `--inspect-share` and a fresh
receipt path. This performs only owner-scoped existing-share OCS inspection and
Depth0 public DAV route probes; successful diagnostic receipt explicitly sets
`backup_roundtrip_proved=false`. Current route uses reviewed lane coordinates;
documented `/public.php/dav/files/{token}` is probed read-only, with and without
Basic auth. Protected shares require their password per official documentation;
no password is inferred or changed. A later repair must follow diagnosed owner
procedure; inspection cannot change lane, shares or provider files.
Actual read-only inventory found neither token nor label in exact folder at
lane KV3. This is not proof of deletion or absence in subfolders. Repair mode
checks all Backup account-owned shares for label ambiguity, verifies exact
folder and account before creating only the reviewed create-only public link.
It requires explicit `--repair-share --expected-lane-version 3 --confirm-repair
"RESTORE Backup CREATE ONLY"`. Existing or new candidate must have exact
owner/path/label/public type/permissions4, known absent password and expiry.
Known share re-read must match. Then actual retained history is encrypted,
uploaded through documented public files route with required header, downloaded
as Backup, independently escrow-decrypted and compared BEFORE CAS. Only token
and URL are changed; every other lane field and all old shares/files preserved.
Fresh receipt keeps share ID and provider proof if subsequent CAS/readback fails.
On retry matching reviewed candidate is reused; stale expected version refuses.
PROPFIND denial alone does not prove grant invalid: create-only policy can deny
read properties. Backup consumers need normal governed credential refresh after
cutover; this is separate from custody history proof and no live rollout occurs.
Producer recovery completed2026-10-03: fresh founder repair receipt proves
current empty revision1/KV1 matches retained baseline, actual encrypted upload201,
Backup readback200, independently escrow-decrypted history match before CAS3->4.
See [safe provider receipt](../../docs/evidence/2026-10-03-root-custody-provider-recovery.json).
Producer plan RPF-WP-0049 finished. Backup runtime consumer refresh remains
activity-core-owned; historical share revocation is separately unverified.
No real custody grant was added.