railiance-platform/docs/net-kingdom-credential-custody-contract.md
codex 2e2c31d237
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
KeyCape factor custody acceptance / acceptance (push) Successful in 7s
Establish scoped KeyCape factor custody and verified automatic renewal
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a092fe-13b1-7f12-ac74-7d258af4d79c
2026-09-13 16:25:33 +02:00

6.8 KiB

NetKingdom credential custody contract

Historical resolver lanes: draft / blocked. KeyCape factor service lane: active, established and verified 2026-09-13 (below). Incident: KEYCAPE-EXPOSURE-20260823-01 Consumer procedure: NetKingdom NK-WP-0033, resolver reconciliation revision eec7007 / checkout f2e578c

This document defines the Railiance-side contract without containing or deriving any credential value. It is not an authorization to fetch, export, apply, or rotate a secret.

Ownership

  • railiance-platform owns OpenBao custody, policy, delivery, rotation metadata, and revocation evidence.
  • net-kingdom owns the privacyIDEA resolver contract and attended consumer reconciliation.
  • ops-warden routes the lane only; it does not fetch or proxy either value.

Required OpenBao metadata (owner must fill, never guess)

Lane Canonical path Field Delivery Status
net-kingdom-lldap-bind-credential REQUIRED_FROM_OPENBAO_OWNER REQUIRED_FROM_OPENBAO_OWNER protected attended input to NetKingdom resolver helper blocked
net-kingdom-privacyidea-admin-token REQUIRED_FROM_OPENBAO_OWNER REQUIRED_FROM_OPENBAO_OWNER protected attended input to provider-admin helper blocked

The owner receipt must also identify the KV mount/version semantics, the least-privilege read/update policy, the authentication method, the expiry or rotation behavior, and the approved attended handoff. No value belongs in this file, State Hub, Git, chat, argv, or ordinary logs.

Consumer handoff

Once the OpenBao owner supplies the metadata above, Railiance-platform records the receipt identifier and passes only protected input to the pinned NetKingdom procedure. The resolver repair must use the minimal two-input --reconcile flow; audit proofs (lookup, MFA, predecessor denial) remain a separate read-only operation.

Current gate

The routing lane is registered but remains resolvable: false. No warden access --fetch, proxy execution, resolver retry, or predecessor restoration is authorized until the OpenBao owner publishes the missing metadata and the attended handoff is approved.

KeyCape factor service lane — authorized setup, 2026-09-13

RPF-WP-0040 / CCR-2026-0023 establish a new dedicated service lane. The user, acting as platform operator, authorized establishing storage/delivery and performed attended OpenBao authentication. This is separate from the historical resolver repair lanes above; their incident receipts are not retroactively completed.

Purpose KV v2 CLI path Fields Consumer
Scoped provider JWT platform/workloads/net-kingdom/keycape-factor-read TOKEN, EXPIRES_AT, REQUEST KeyCape via namespace-scoped ESO and adminTokenFile
Renewable service login platform/workloads/net-kingdom/keycape-factor-issuer USERNAME, PASSWORD, REQUEST Owner bootstrap, then dedicated renewal worker; never KeyCape

Provider identity: keycape-factor-reader (local privacyIDEA service admin). Effective permission: tokenlist for realm coulomb only. Preserve the existing no-admin-policy baseline for other administrators using an explicit fallback that excludes this service identity. Only the two reviewed named policies may be introduced; unexpected existing admin policies abort setup.

Generate the service password in owner-process memory and persist with KV CAS=0 before provider creation, allowing interrupted setup to resume. The attended worker passes values through stdin/captured pipes only, never argv or receipts. Only explicit KV absence permits creation. Existing request provenance and policy definitions must match; retries do not rotate an existing identity.

Reader policy: workload-kv-read-keycape-factor-read, role keycape-factor-workload-kv-read, bound sso/keycape-factor-eso, audience openbao, 15-minute maximum OpenBao session, no default policy. Metadata apply/readback passed via the attended owner envelope. Provider issuance, native ESO delivery, KeyCape mounted-file activation, per-user lookup and rotation without restart passed. The reader can inspect and revoke only its own OpenBao session in addition to reading the exact JWT data/metadata paths. See the acceptance record docs/evidence/2026-09-13-keycape-factor-custody.md.

Provider JWTs expire independently of OpenBao sessions. Require 5 minutes to 2 hours remaining lifetime at issuance; renew well before expiry. Disable the service's tokenlist policy (while retaining fallback exclusion) to withdraw its factor access; do not rotate privacyIDEA's global signing key as routine renewal. Verify expiry/permission refusal separately from OpenBao self-revocation.

Renewal: sso/keycape-factor-renewer runs every ten minutes under its own service account, with a five-minute maximum OpenBao session. Its separate policy reads the issuer password and reads/writes only the delivered JWT path. The worker verifies provider identity, expiry, factor lookup and denied policy administration before a CAS write and readback, then revokes its session. ESO refreshes once per minute. KeyCape mounts only admin-token, mode 0440, through fsGroup 65534; the issuer password never enters its namespace Secret.

Operations: make keycape-factor-tests runs offline failure/retry and config preservation tests. make keycape-factor-live-acceptance creates bounded Jobs that verify native delivery scope and a second renewal reaching the mounted file. The runner emits booleans and resource identifiers only. CronJob failures and ExternalSecret Ready=False are the native degraded-state signals. A failed renewal leaves the last verified token in custody; expiry causes authentication to fail closed. Restore provider/custody connectivity and launch a renewal Job from the CronJob; verify SecretSynced and repeat live acceptance.

Attended setup is reproducible through openbao-attended-exec.py with keycape_factor_metadata.py --apply --receipt <new-file>, keycape_factor_bootstrap.py --receipt <new-file> and keycape_factor_renewal_metadata.py --receipt <new-file> in that order, followed by the custody manifest and guarded keycape_factor_activate.py --apply. Use unique receipt paths. Existing mismatched policies/roles/provenance fail closed; never replace an unknown owner credential. The separate keycape_factor_eso_metadata.py records the migration from initial read-only metadata to ESO's self-session permissions; fresh setup uses the final policy.

Outstanding acceptance is explicit in RPF-WP-0040-T04: genuine provider JWT expiry and provider-policy revocation/recovery drills. A newly issued JWT does not itself revoke its predecessor. Native mounted rotation has passed, but it is not evidence of predecessor revocation. Optional MFA rollout and lost-factor recovery remain KEY-WP-0035 / USER-WP-0030, not completed by this service lane.