access-engine/docs/task-execution-pdp-consumer-contract.md
tegwick 7ad8dec85e
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 1m33s
Publish reviewed exact task execution PDP binding contract
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
2026-10-11 15:03:03 +02:00

7.4 KiB
Raw Blame History

Exact execute-ccr PDP consumer integration (source preparation)

Access source baseline: c829e53030. No native readiness or formal owner assent is established by this staged artifact.

Existing interface, without a new grant API

Use POST /v1/check with CheckRequest, DecisionEnvelope and the existing served approval claim/consume APIs. pkg/api/canonical.go already hashes nested context values, including an execution_contract object. No new canonical digest function or access-engine execution ledger is needed. Access owns policy decisions only; Secrets owns PEP lifecycle and one-shot admission, Platform owns OpenBao custody.

The published request action for the new CLI must be execute-ccr, resource secret-catalog-lane under system secrets-engine, id catalog:, stage prod and tenant tenant:platform. CLI execute-ccr must never send apply: shipped lifecycle v2 accepts apply while ignoring all execution_contract contents. That existing grant is not the reviewed metadata execution contract. Preserve existing 12-action behavior and add a separate owner-reviewed exact execute-ccr policy version/action declaration and denial tests before publication.

The proposed policy must enforce human_control true, served approval kind/issuer/ valid_now/human_control/pdp_path, closed contract_version and metadata-apply-ccr, nonempty exact operation_id, bounded deadline/budget, explicit target/body/catalog/ CCR/grant/source hashes and trusted principal representation. Hash existence is shape, not provenance: body equality and owner-source reconstruction remain PEP obligations. Policy cannot compare its own post-evaluation request digest. Unknown action, missing contract/approval, foreign principal and older package must refuse. A package/version pin is validated in envelope provenance, not hashed as an authority field: api.RequestDigest excludes request.policy_version.

Mandatory digest joins

  1. Compile owner sources and catalog into the complete claim-free request. All execution fields are inside context.execution_contract before issue Check. Use context.purpose for consumer purpose. Top-level purpose is reserved for advisory readback and enforcement /v1/check refuses it.
  2. Issue approval against claim-free Check's enriched binding.request_digest. Approval Engine records that value as claim.binding.pdp_digest.
  3. Fetch the live served claim, attach it only at context.approval, and Check the exact same request again. Retain the submitted request in owner memory.
  4. PEP validates binding.submitted_request_digest against its submitted request; binding.request_digest against the returned enriched binding material; and claim.binding.pdp_digest against binding.approval_binding_digest. The latter is the enriched request with only top-level context.approval removed. It does not remove execution_contract, human_control, catalog_target or purpose.
  5. Validate signature/served authenticity using existing configured PEP path, provenance package/version, caller record, registry snapshot, allow lifetime, live claim freshness, and exact subject/action/resource/tenant/context. Registry enrichment can alter subject/resource attributes: do not compare locally computed claim-free digest to claim.pdp_digest.
  6. Consume once with approval_id, full enriched binding.request_digest and exact decision_id. Approval Engine's consume checks request digest format/CAS, not semantic correspondence to issue pdp_digest; steps 1–5 are mandatory. Independently read the durable approval consumption triple through the authenticated owner route and match it before OpenBao. Idempotent response is never fresh admission.
  7. A changed operation UUID/method/path/body/source/catalog/subject yields a different approval-free digest; require a fresh exact approval. Retries only return final stored receipt. Unknown consume/backend outcomes require recovery.

Minimal consumer code delta

Secrets authorization.build_action_request gains a strict optional keyword-only execution_contract parameter. validate/compile it in Secrets' owner compiler, then deep-copy it into context. Reject a contract on any action except execute-ccr, reject execute-ccr without the contract. Set human_control true on this action regardless of legacy catalog default. Catalog_target remains included.

Thread the SAME validated object through approval_consume._expected_request, resolve_approval_observation and authorize_action. Today _expected_request rebuilds from cfg/entry and drops any caller-added context; merely adding context in CLI would not reach the claim/PDP join. No arbitrary caller request/body injection. Require the execution boundary's verified initiator identity, not cfg/environment strings, and exact package/version configuration for execute-ccr. Return the existing ConsumeBinding and confirmed ConsumedApproval, never an opaque approval label. require_production_consume runs only in owner child after admission reserve.

Platform independently recompiles exact operations and compares full digest, then invokes the reviewed Secrets consume path at the actual effect boundary. Its persistent one-shot ledger requires unique approval+digest and durable states before each external call. This ledger and restricted backend do not currently exist; audit outbox and bare consumed bool do not substitute. No unrestricted subprocess, generic OpenBao apply, caller ACL/HCL, path override or bearer return.

Principal and route truth

values/secrets-engine.yaml enforces Kubernetes TokenReview for system:serviceaccount:secrets-engine:secrets-engine representing protected system secrets-engine. This authenticates transport caller/system correspondence only: internal/callerauth/auth.go does not bind CheckRequest.subject to that identity. The v2 policy separately admits only subject secrets-engine/type service. A caller-authored initiating human is neither authenticated by this path nor an admitted v2 subject. An explicit identity-owner verified representation contract plus policy grant is required before actual initiating-principal design can ship. Do not rename service:secrets-engine to secrets-engine silently; authentication service subject and PDP principal have different published vocabularies.

FLEX-WP-0023 records historic enforce-mode positive/negative native caller proof. This is source evidence of an existing route, not a current live probe. Operator CLI access needs attended admitted TokenRequest/tunnel/network path; in-cluster DNS is not a workstation route. No token was requested and no native query ran. FLEX-WP-0036 runtime rename remains active: keep existing flex-auth coordinates until exact consumer transition is separately admitted. No new executor route, metadata CCR, task execution grant, source pin, real native effect, cleanup proof, principal representation or steady-state workflow adoption is supplied by this stage. RPF35-T02 and Secrets T06 must remain open.

Verified source tests

Run go test ./pkg/api ./internal/policy -run ExecutionContract -count=1 in staged source. API tests cover ten changed semantic fields, claim attach/removal, registry enrichment and correlation ID irrelevance. Policy test runs actual v2 Rego: execute-ccr denies unknown_action, fake execution context on apply still allows (demonstrating the semantic gap), human principal denies wrong_subject_type. These characterize shipped behavior and digest integration; they do not claim new entitlement policy or executor is shipped.