railiance-platform/docs/credential-lane-designs/secrets-engine-task-execution-entitlement.md
codex e50a0d1890
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s
Record service JWT review defects and scoped execution entitlement design
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
2026-10-11 14:04:48 +02:00

11 KiB

Secrets Engine task execution entitlement — Platform owner design

Prepared under RPF-WP-0035-T11; implementation belongs to RPF-WP-0035-T12. This is a proposed source design, not an installed endpoint, approved CCR, founder disposition or native acceptance. CCR-2026-0038 stays login-self-only. No service default changes and no standing service administrative ACL.

Existing machinery and exact first action

Platform INTENT §§ Stable Interfaces, Secure Custody and Operable/Observable require a stable constrained backend interface. Platform owns OpenBao enforcement and credential lifecycle; KeyCape owns identity, access-engine decides, approval-engine consumes, and Secrets Engine owns the lifecycle PEP. Platform is Staff with declared Tooling gaps, not a replacement identity or authorization engine.

Current cli._require_lane_approval consumes before _open_backend, which gives apply_plan the login-self token. That token cannot read/write target ACLs or AppRole roles. Login proof cannot complete functional Lifecycle adoption.

First action: a new explicit execute-ccr interface applying exactly one reviewed workload-kv-read CCR's two structure objects: its generated reader ACL and one OIDC/Kubernetes role on an existing mount. Refuse mount enable/config, AppRole, KV data/metadata operations, SecretID issuance, token delivery, arbitrary argv, free-form policy bodies, broader typed CCR dispatch and generic apply_plan. Generic Secrets Engine apply supports mount/AppRole work; silently translating that action to this owner interface would change its meaning.

Reuse credential-change.py's workload-kv-read validator, generated policy, auth_payload, readiness/binding checks and metadata applier structure. Existing service-jwt-login remains identity only; existing custody-generate-grant supplies patterns for exact generated policy/issuer/token-role TTL/no-default/cleanup, but its platform/workloads/keycape/+ create grant cannot perform structure writes. A new separately reviewed request type task-execution-grant is necessary; it is not yet in LANE_MODULES, so presenting it today must be refused.

Bound request and interface

Proposed version platform-task-execution/v1, initially a founder-attended owner primitive, not an unattended HTTP service. Input is a bounded private pipe containing a non-secret request envelope; service authentication is a separate memory-only credential channel. No credential enters command argv, environment, receipt or Git. The owner launches the exact reviewed primitive through the existing attended platform-admin envelope only after the scoped founder go is recorded.

Envelope fields: unique operation_id; action=execute-ccr; platform realm and stage; service principal service:secrets-engine of type service; consumer catalogue revision/hash; exact CCR id/content SHA256; all authoritative generated source/body SHA256s; ordered endpoint/method/payload digests; exact canonical CheckRequest and its digest; served approval id/claim binding; PDP DecisionEnvelope id/package/version, not-before/expiry; successful consume binding; owner admission/source revision. The canonical request includes operation id, CCR digest, catalogue digest and the whole target/body plan, not merely a friendly lane name. Local owner files are the source; supplied payloads, file paths or HCL are never applied. Secret-bearing request fields and unknown fields are refused.

Action/PDP spelling is a new consumer contract to publish with access-engine. Reuse its canonical digest/claim validation, do not invent an interchangeable apply decision. Service identity and caller subject are independently matched; a caller assertion of service:secrets-engine, a decoded JWT or a successful human OIDC login is insufficient. Authenticate against CCR38's exact native role and independently verify lookup creation path, role, effective token/identity policies and service entity provenance. If the existing metadata does not bind subject adequately, use KeyCape signature/issuer/audience/expiry validation plus owner-correlated native role login; do not label role-only metadata a trusted subject.

Admission, consume and execution ordering

  1. Secrets Engine and Platform perform only local/static checks and public unauthenticated discovery before consume: envelope/schema, owner CCR readiness, exact source hashes, generated policy/role equality, full target/body plan, owner primitive revision, journal availability and available bounded lifetime. The founder's independently approved owner envelope is separate bootstrap authority; it grants no consumer lifecycle action by itself.
  2. Platform durably reserves (approval_id, request_digest, operation_id) with a unique constraint and confirms the exact plan. Journal write must be fsynced and atomic before acknowledgement. No database content is copied to evidence.
  3. Secrets Engine obtains validated claim/PDP correspondence and performs the existing approval-engine CAS consume for that same request. No protected consumer login, client-secret read or backend write precedes this step. Platform accepts neither a caller boolean nor an unsigned copy as proof: it independently validates the served claim/PDP and verifies consume with approval-engine's authenticated replay/verification contract. If this is unavailable, it refuses execution.
  4. Bind the authenticated service identity after successful consume. Authenticate once; refusal or timeout burns this admission. Platform atomically transitions the same reservation to consume-confirmed, then applying before any effect. A racing second call cannot acquire the state. Consume idempotency is not permission to execute twice. Repeated calls return the recorded terminal receipt only.
  5. Inside the founder owner envelope, mint an owner-held ephemeral task token with only exact target paths. Apply exactly the pinned typed plan, compare value-free native readback, revoke the task token, remove only this operation's temporary grant role/policy after revoke, and finalize the durable receipt.

New approval-engine verification/replay semantics and owner journal are required implementation gates. They are not supplied by current ConsumedApproval dataclasses or caller receipts. If approval-engine offers only idempotent consume, Platform may make the authenticated same-digest consume call itself after the client call, but must verify exact original correspondence and keep the independent execution journal; never interpret idempotent success as a fresh admission.

Journal states: reserved → consume-confirmed → applying → verified|failed|unknown. Consume/auth failures become failed; uncertain consume, lost post-write response, crash after applying, or cleanup failure become unknown. None automatically re-executes. A retry requires owner reconciliation, native readback and a fresh approval/operation id if another effect is needed. No rollback reuses the consumed approval; retain partial state and prepare a separately approved exact recovery.

Backend policy, payload and time enforcement

Ephemeral role/policy names derive from the operation hash and are owner-controlled. Proposed token: service, orphan, nonrenewable, no default/identity policies, TTL and explicit maximum at most 120s, and 12 uses maximum including cleanup. Actual expiry is the earliest approval/PDP expiry, founder window expiry, authenticated identity/session expiry and now+120s; refuse insufficient remaining time. Budget is a reviewed fixed operation plan, never an arbitrary caller num_uses. Reserve at least one self-revoke use and refuse exhausted/expired executions.

Grant endpoints are exactly sys/policies/acl/<CCR reader policy> and auth/<CCR existing mount>/role/<CCR role> with only required read/create/update; self lookup/capabilities/revoke have explicit minimal grants. Explicit deny applies to guarded client-secret data/metadata, token create/renew, secret-id and all unrelated structure targets. Do not publish blanket deny on all ACL paths if it would also override the two intended target grants. The target-set allowlist and native denied sibling/admin/data probes define this exact scope.

The founder-held issuer may mint only the unique task role; the service role never receives issuer/token-create authority. Existing platform-admin bootstrap remains founder-attended; no persistent administrative credential is introduced for Secrets Engine. No task token is returned to the caller or reused by generic _open_backend. Returning one would allow direct OpenBao bypass of lifecycle checks.

OpenBao ACL limits endpoint paths/capabilities, but cannot constrain the HCL or role JSON body or bind an approval digest by itself. Independent Platform mediation validates the exact body hashes against locally generated owner-approved source immediately before each call; this is part of backend enforcement. A policy-write token exported to a caller would let it replace the target ACL with broad powers, and an auth-role-write token could bind a privileged policy. Therefore raw exact-path ACL is not sufficient execution authority. Native ACL probes prove endpoint scope; independent mediator counterexamples must prove body/action/approval scope.

Evidence, acceptance and rollback

Value-free receipt: proposal/source/CCR/request/decision/consume/journal digests, principal fingerprint and role, reserved/executed timestamps, fixed endpoint/payload hashes, native request ids or safe hashes, readback equality, task/session accessor fingerprints, exact granted TTL/uses, revoke and temporary-object cleanup booleans, terminal state. No raw tokens, JWTs, full accessors, errors, KV responses or secrets. Receipt return is separate from protected-action success: unknown cleanup never reports verified. Retain outcome after client disconnect for safe read-only recovery.

Required implementation and native proofs: intended disposable metadata-only action passes once; wrong identity/type/issuer/audience/claims, altered CCR/catalogue/body, wrong action/target, stale revision, TTL/use exhaustion, invalid/expired/mismatched PDP or consume, missing journal, racing/replayed request, direct raw-token sibling write, policy-body escalation and role-policy substitution all refuse. Crash/timeout at reserve/consume/mint/write/readback/revoke/temporary cleanup must preserve unknown and prevent retry. Native ACL denials and mediator refusals must be distinguished from transport failure. Restore/delete only the disposable objects by their owning reviewed recovery action; never broaden the service policy to discover gaps.

The initial pilot does not cover provision/rotate/handoff/wrap/exec/deactivate, KV destruction or the existing generic AppRole apply. Each needs its own typed operation/body contract and owner evidence. Full steady-state adoption additionally needs dispatcher integration, real intended result and accounting/reservation reconciliation, credential-free caller execution and reviewed default migration. RPF35-T02 and Secrets T06 cannot close from the login verifier or this design.