access-engine/docs/trusted-service-task-source.md
tegwick 2b064eee51
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Container Image / build-and-push (push) Failing after 1m10s
Bind trusted task approval to exact producer facts and lifetime
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
2026-10-16 17:27:30 +02:00

108 lines
7.4 KiB
Markdown

# Trusted service task source proposal (v2)
The separate `secrets-engine.task-execution.service-pilot` v2 source package can
return ALLOW only through the existing `/v1/check` typed task path. The original
v1 package remains unchanged and DENY-only. No chart, runtime, source identity,
credential custody or native execution admission is enabled by these sources.
The server requires enforced TokenReview, audience `flex-auth`, the exact retained
Secrets service-account mapping, mounted envelope signing configuration and an
owner-installed `--approval-source-file`. This public configuration contains
`source_id`, `source_revision`, fixed HTTPS `origin`, `store_tenant` exactly
`tenant:platform`, absolute `ca_file` and absolute mounted `token_file`. The
credential must independently carry existing Approval `approval:read` authority
for that store. Source labels describe the owner-admitted configuration; they do
not perform its admission. No key or token value belongs in the configuration.
The reader sends one authenticated GET to the fixed
`/v1/approvals/{UUID}/claim` endpoint, accepts only bounded strict JSON, uses only
the configured CA, refuses redirects and environmental proxies, and has a total
three-second HTTP timeout. It neither creates nor approves nor consumes. Mounted
bearer files must be regular, bounded and have no group write or other access;
0440 is supported. Public configuration/CA files also refuse group/other writes.
Errors do not include response bodies, credentials or transport diagnostics.
The unchanged Approval-owner pure data helper is copied with exact source pins
under `third_party/approvalfact`. The fixed reader establishes provider origin;
the helper establishes schema and semantic correspondence. Both original and
fresh claims must independently be currently valid, unconsumed, human-controlled
PDP-path claims for the exact UUID, native five-field act and Access approval-free
request digest. Nonfreshness authority must match exactly. The freshly fetched
claim never replaces the submitted claim/context or renews original freshness.
The native act derives from the normalized subject/resource, fixed service
principal, action and nonempty `context.purpose`. The HTTP decoder and task registry
loader preserve raw JSON numeric representations. Registry facts loaded through
the old lossy profile cannot enter the trusted path. Only the Approval-owner
helper canonicalizes native act data. Existing PDP full/submitted/approval-free
digests retain their published numeric profile through a digest-only legacy
projection; the signed structured binding retains the original numeric kinds.
Inputs unsupported by that existing PDP profile refuse; this proposal does not
weaken any consumer numeric admission or invent numeric restrictions.
The same existing policy evaluator decides after those joins. Generic check,
batch and list entry points refuse task execution across all policy names. No
request-selected verified flag, provider origin or policy enable switch bypasses
the typed path. Missing approval can receive signed DENY for preapproval binding;
ALLOW requires authenticated matching original/fresh claims. Its expiry is exactly the immutable operation deadline, after validating that
it fits the source-selected 120s hard maximum and every caller/original/fresh
freshness/approval bound. At least the declared backend TTL plus the existing
5s cleanup reserve must still fit after source I/O and final evaluation. The
source maximum conservatively matches the existing 120s task-token cap; the
structural backend budget maximum is not a promise every budget can fit. In
particular backend TTL120 cannot fit this authority ceiling plus reserve. A
fractional operation deadline is retained exactly rather than rounded earlier.
Approval's default 30s observation freshness cannot cover the minimum30+5
operation budget. A separate owner-admitted source configuration must explicitly
supply adequate original/fresh observation lifetime; fetching anew cannot renew
an original claim. The disposable reviewed proof uses backendTTL30, immutable
operationdeadline+60s and explicitly configured Approval freshness120. This is
an entire-operation authority interval, not a decision-to-start window. Platform
must retain native-entry and per-call deadline/cleanup gates; delays simply refuse. Existing source-owned signing covers the
original binding and new `provenance.approval_observation` receipt. The receipt
contains source/configuration identity, exact fetched-byte digest, native digest
and observation/validation/deadline timestamps. JSONL readback and outbox replay
preserve producer numeric signatures; no second signing algorithm is introduced.
Packaging must copy the local owner helper before `go mod download`. Existing
ordinary image CI triggers include `third_party/**` so a helper update cannot
silently leave the old image. No build publication is invoked by this preparation.
Rollback selects the unchanged v1 package or removes the v2 admission; generic
fallback remains refused. Rotating/withdrawing source or signing trust is a
separate owner-admitted runtime operation. The earlier Platform positive proof
remains evidence only at its old ec21518e Access pin; its generic synthetic policy
is deliberately incompatible with the successor guarded source.
## Producer normalization before Approval issue
The retained registry enriches Secrets subject attributes. Consequently the
submitted approval-free digest is not the evaluated approval-free digest. This
is the existing `docs/request-enrichment.md` contract, not a reason to remove
registry facts or copy its enrichment rules into Secrets.
The existing `/v1/check` typed v2 path accepts the exact original claim-free
proposal and returns a signed DENY containing the authoritative normalized
binding and original `submitted_request_digest`. For this v2 path it also emits
`approval_binding_digest` when claim-free, equal to evaluated `request_digest`.
That is a normalization receipt supplying facts only. It has no ALLOW lifetime
and cannot satisfy execution authorization. Before issue, Secrets authenticates
this receipt using its existing independent producer trust/policy/source pins,
checks original request/context correspondence, caller/deadline/current-time
bounds and normalized self-digests, then derives the native act and issue digest
from the authenticated producer binding. It does not supply expected registry
facts or expected digests to the producer. The Approval API records these exact
facts at issue; human approval follows its unchanged authenticated contract.
The submitted proposal remains unchanged; the final request attaches only the
original issued claim. Final ALLOW rechecks independent source facts, native/PDP
correspondence, normalization and all temporal/caller conditions. A changed
registry cannot silently refresh or replace an approved act: a changed evaluated
digest/native target refuses even when the freshly fetched claim is still valid.
The source tests cover the retained registry, signed DENY/ALLOW separation,
original/evaluated digest distinction, unchanged context, source/registry pins,
registry drift, stale/refreshed claims and exact response/record parity. Earlier
empty-registry proofs remain explicitly scoped historical source fixtures.
R3 retains precise decision `not_before`; it does not floor that lower bound to
mask Approval's current whole-second consumption receipt defect. Approval-owner
precision repair and full owner integration remain separate reviewed evidence.