--- id: SECRETS-WP-0007 type: workplan title: "Production-safe provisioning, authorization, and lifecycle hardening" domain: infotech repo: secrets-engine status: ready owner: codex topic_slug: custodian created: "2026-08-23" updated: "2026-08-23" --- # SECRETS-WP-0007 - Production-safe provisioning, authorization, and lifecycle hardening ## Goal Close the highest-risk gaps between the proven CLI MVP and the production workflow described by `INTENT.md`, before expanding secrets-engine into a service or moving additional high-risk lanes from interim routing to native operation. The source assessment is `history/2026-08-23-scope-intent-capability-gap-assessment.md`. The most relevant gaps are: 1. single-field `bao kv put` can replace siblings on a multi-field path and puts the value in the local subprocess argument vector; 2. KV `revoke` destroys metadata while leaving policy/AppRole access behind, and its dry-run does not match live behavior; 3. production approval checks are coarse status checks, accept local fixtures, and do not bind actor, action, lane, fields, expiry, or dual control; 4. AppRole delivery tokens are not explicitly revoked after exec/verification; 5. route and verification can attest only the first field and use a garbage token rather than a real unrelated identity for KV denial; 6. evidence is best-effort and incomplete on failure paths. ## Scope and sequencing This workplan hardens the existing CLI contract first. It covers KV write transport and merge semantics, lifecycle command semantics, decision binding, short-lived delivery sessions, verification/readiness, and evidence. It then provides the safe implementation gate for resuming `SECRETS-WP-0006-T05/T06`. The first task is containment. No task may exercise live production values to develop or test a primitive. Use fake values and a throwaway OpenBao instance until the relevant behavior has passed unit and integration tests. Existing ESO, Kubernetes/OIDC delivery, provider rotation, and application health remain with their current owners. ## Non-goals - A service API, daemon, UI, scheduler, or remote multi-user protocol. - Runtime tenant authentication, quotas, or a tenant control plane. - A second custody backend or backend-portability project. - Provider-specific rotation automation. - Replacing flex-auth, State Hub decisions, key-cape/user-engine identity, ops-warden routing, ops-bridge transport, or OpenBao enforcement. - Unparking the standalone `warden-sign` AppRole as a break-glass path. Service mode remains deferred until the exit criteria here are satisfied; it must not expose the current bootstrap and lifecycle shortcuts as an API. ## Safety invariants - No raw value in Git, State Hub, chat, prompts, workplans, evidence, normal logs, environment diagnostics, or a subprocess argument vector. - No write to a shared multi-field path unless sibling preservation is proven. - No destructive metadata deletion through a command presented as ordinary revoke/deactivate. - Production actions require canonical, exact-action approval. Offline fixtures cannot authorize steady-state production mutations or delivery. - Existing workload delivery stays in place until separately approved owner coordination says otherwise. - Tests use fake values and throwaway OpenBao only; live checks are metadata/capability-safe and approval-gated. ## Contain unsafe lifecycle surfaces ```task id: SECRETS-WP-0007-T01 status: todo priority: high ``` Add immediate fail-closed guards before implementing replacement primitives: - reject `provision` on an existing multi-field lane; - reject or rename the current destructive KV `revoke` path so it cannot be mistaken for soft deactivation; - make KV revoke dry-run render exactly the operations the live path would run; - document that `SECRETS-WP-0006` may apply/verify metadata but must not provision or revoke shared values through the current commands. Acceptance: - A regression test proves no backend call occurs for multi-field existing-lane provisioning. - A regression test proves dry-run and live operation plans contain the same KV, AppRole, and policy targets. - The destructive action requires an explicit name/flag and a separately approved action; ordinary revoke cannot destroy KV metadata. - CLI/help/runbook language no longer describes metadata deletion as reversible deactivation. ## Implement merge-safe, non-argv provisioning ```task id: SECRETS-WP-0007-T02 status: todo priority: high ``` Replace the raw `field=value` subprocess call with a backend write primitive that never places the value in argv and safely updates one or more declared fields without removing unmentioned siblings. The design may use OpenBao CAS, a merge/patch operation, an input file reference with strict cleanup, or direct request input, but it must remain isolated behind `OpenBaoClient` and preserve the catalog field allowlist. Acceptance: - Unit tests inspect the complete subprocess request and prove the fake value is absent from argv, environment, output, exceptions, and evidence. - Throwaway OpenBao integration proves updating one field preserves every sibling field and fails closed on a CAS conflict. - Multi-field input is atomic from the caller's perspective; a partial failure cannot silently leave an unreported mixed version. - Source and generated inputs retain mode/path guards and guaranteed temporary cleanup. - Production generation remains forbidden, and high-risk production provisioning is still decision- and dual-control-gated. ## Split suspend, deactivate, and destroy semantics ```task id: SECRETS-WP-0007-T03 status: todo priority: high ``` Replace the overloaded `revoke` behavior with explicit lifecycle operations and plans. Define at least: - **suspend delivery**: stop minting new native delivery sessions while preserving custody and a documented rollback; - **deactivate native access**: remove/disable the lane AppRole and consumer policy without deleting the KV value; - **revoke issued sessions**: revoke known tokens/leases by non-secret accessor where the backend supports it; - **destroy custody metadata**: irreversibly delete KV metadata/versions only through an unmistakable, separately approved action. Preserve compatibility only where it cannot mislead. A legacy `revoke` alias may map to a safe non-destructive action; it must never silently retain the current destructive meaning. Acceptance: - Each operation has a guarded dry-run plan, exact targets, distinct approval action, non-secret evidence, and documented rollback/irreversibility. - Dry-run and live use the same plan object rather than separate handwritten descriptions. - Integration tests prove suspend/deactivate preserve KV data and destroy does not run without its explicit approval and confirmation contract. - Auth-capability and KV lanes have coherent but kind-appropriate behavior. - Existing workload delivery is reported as an external dependency and is not deleted by native lifecycle commands. ## Bind approvals to exact production actions ```task id: SECRETS-WP-0007-T04 status: todo priority: high ``` Define and enforce the decision contract needed by production commands. A resolved approval must bind at least: - canonical decision UUID and non-superseded status; - catalog id and stage; - action (`apply`, `provision`, `verify`, `exec`, `handoff`, `suspend`, `deactivate`, `destroy`, or later `rotate`); - exact field set or policy/auth targets where applicable; - requesting actor/purpose and expiry or bounded execution window; - required approval count and distinct approvers for `dual-control`. Coordinate the external object shape with State Hub/flex-auth rather than inventing authorization ownership in this repo. Keep local fixtures for throwaway demos and non-production tests only; require an explicit unsafe-demo switch if they remain reachable at all. Acceptance: - Every privileged production handler passes an action-specific request into one shared authorization function. - Tests reject wrong lane, stage, action, field set, actor/purpose, expiry, superseded status, insufficient approvals, duplicate approvers, and local production fixtures before any OpenBao call. - `approval.model: dual-control` has enforced semantics rather than being a label. - Catalogs use resolvable canonical decision UUIDs for live actions; legacy CCR references remain provenance, not executable authorization. - State Hub outage fails production actions closed while dry-run/catalog inspection remains usable. ## Make delivery sessions short-lived and explicitly closed ```task id: SECRETS-WP-0007-T05 status: todo priority: high ``` Refactor AppRole login into a scoped session object that retains only the minimum non-secret lifecycle handle needed to revoke the issued token in a `finally` path. Apply it consistently to exec, KV verification, auth-capability verification, and any future file/wrapped delivery. Define the steady-state OpenBao authentication interface separately from the delivery AppRole. Bootstrap token files remain an explicit break-glass/setup provider; add a bounded OIDC/service-auth provider only with railiance-platform and identity-owner review. Acceptance: - Success, child non-zero exit, setup failure, verification failure, SIGINT, and SIGTERM tests all attempt token revocation and clean temporary material. - Secret IDs remain single-use where configured; tokens retain TTL/use limits as backstops rather than their only cleanup. - Evidence records session establishment/revocation outcome using non-secret handles or request ids only. - A failed revocation is visible and actionable without printing token or accessor material. - Bootstrap-file authentication is clearly separated from the reviewed steady-state provider and cannot become an implicit fallback. ## Strengthen verification, readiness, and evidence ```task id: SECRETS-WP-0007-T06 status: todo priority: high ``` Make verification and routing truthful for multi-field and high-risk lanes: - verify every declared field unless the exact approved subset is explicit; - make route readiness require every required field, not only the first; - replace the garbage-token negative check with a reviewed real unrelated identity/token or a capabilities-based denial proof that can detect policy overlap; - record attempt, success/failure, cleanup, and authorization outcome for every privileged command; - correlate engine evidence with OpenBao audit request ids where available; - provide a non-secret lane audit summary over local/State Hub evidence. Acceptance: - Removing any required sibling field makes readiness false and identifies only the missing field name, never values. - Negative verification fails when a deliberately overlapping unrelated policy is introduced in throwaway OpenBao. - Evidence tests cover backend exceptions, child failures, State Hub delivery failures, and cleanup failures without leaking fake secret patterns. - An audit/report command summarizes decisions, attempts, outcomes, and cleanup for a lane without becoming an authority or replacing OpenBao audit logs. - The full test suite and throwaway OpenBao integration suite pass. ## Resume native production lane adoption ```task id: SECRETS-WP-0007-T07 status: wait priority: high ``` Dependency: T01-T06 complete, then explicit per-lane approvals and scoped production authority from railiance-platform. Resume `SECRETS-WP-0006-T05` lane by lane. Apply only the exact native policy and bounded AppRole, verify every field plus unrelated-consumer denial, confirm the existing workload delivery remains healthy, exercise only an approved value-safe child command, and record rollback/session-cleanup evidence. After a lane passes, complete `SECRETS-WP-0006-T06` with ops-warden. Retire its interim proxy only after both parties agree that native readiness evidence is complete. Do not batch-retire all five lanes. Acceptance per lane: - Canonical action-bound approval is resolved and linked. - Policy/AppRole server readback matches the reviewed exact-path plan. - All declared fields pass presence/access checks; a real unrelated identity is denied; no value enters evidence. - Issued delivery sessions are explicitly revoked and cleanup is evidenced. - Existing ESO/OIDC delivery and application health remain good according to their owners. - Rollback is rehearsed or capabilities-safe verified before proxy retirement. - ops-warden routing reports native readiness and removes only that lane's interim proxy. ## Dependencies and coordination - `SECRETS-WP-0006` owns the five-lane catalog admission and live cutover. - railiance-platform owns production OpenBao authority, custody, and backend audit. - State Hub/flex-auth own the canonical decision/authorization contract. - key-cape/user-engine own human/service identity and claims. - Workload owners own ESO/Kubernetes delivery and provider/application health. - ops-warden owns credential routing and interim proxy disposition. Any external contract change must be recorded as non-secret evidence and must not transfer custody or authorization ownership into this repository. ## Exit criteria - Current unsafe multi-field provisioning and misleading revoke behavior are contained and replaced. - Raw values cannot enter subprocess argv or evidence through provisioning. - Production approvals are canonical, exact-action, expiring, and genuinely dual-control-capable. - Delivery tokens are explicitly revoked on every exit path. - Readiness and verification cover all declared fields and meaningful unrelated identities. - Lifecycle operations distinguish reversible access suspension from irreversible custody destruction. - At least one of the five admitted production lanes completes the hardened native verification/cutover path; remaining lanes have explicit external blockers rather than engine-safety blockers. - Service-mode design remains deferred until these guarantees are demonstrated.