Bind trusted task approval to exact producer facts and lifetime
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

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
This commit is contained in:
tegwick 2026-10-16 17:27:30 +02:00
parent 4f6946bbb3
commit 2b064eee51
31 changed files with 2170 additions and 30 deletions

View file

@ -0,0 +1,8 @@
- id: unsigned-service-caller-not-authority
request:
tenant: tenant:platform
subject: {id: secrets-engine, type: service}
action: execute-ccr
resource: {id: catalog:test, type: secret-catalog-lane, system: secrets-engine}
context: {human_control: true, runtime_admission: true, verified: true}
expect: {effect: deny, reason: service_execution_contract_unmatched}

View file

@ -0,0 +1,120 @@
---
id: secrets-engine.task-execution.service-pilot
name: Secrets admitted service task execution
namespace: secrets-engine:secret-catalog-lane
version: v2
status: proposed
package: flexauth.secrets_engine.service_task_execution
allow_ttl: 120s
actions: [execute-ccr]
owner: team:platform-security
fixtures: [policy_fixtures.yaml]
caring:
profile: caring-0.4.0-rc2
enforce: false
activation:
mode: local
---
# Trusted service task source successor
This source package is evaluated exclusively by the typed v2 HTTP path. That
path requires exact TokenReview caller mapping, immutable numeric source
representations, a fixed authenticated Approval reader, separate original and
fresh claim validation and native/PDP correspondence before policy evaluation.
Its 120s declared TTL is a hard source ceiling, not a blanket grant. The typed
path derives actual expiry exactly from the immutable operation deadline and
requires the entire declared backend TTL plus the existing 5s cleanup reserve
within original/fresh claim, approval and caller bounds. Budgets that cannot fit
refuse; the 120s structural backend maximum is not guaranteed admissible.
Generic check, batch and list routes refuse task execution. Selecting this source
package alone cannot bypass those joins. No deployment or trust admission is
established by this package. The v1 package remains unchanged and DENY-only.
```rego
default decision := {"effect": "deny", "reason": "service_execution_contract_unmatched"}
decision := {"effect": "allow", "reason": "exact_task_execution_matched"} {
candidate_matches
}
hash_ok(x) { is_string(x); regex.match("^sha256:[0-9a-f]{64}$", x) }
candidate_matches {
input.action == "execute-ccr"
input.tenant == "tenant:platform"
input.subject.id == "secrets-engine"
input.subject.type == "service"
input.resource.system == "secrets-engine"
input.resource.type == "secret-catalog-lane"
input.context.human_control == true
c := input.context.execution_contract
c.contract_version == "SECRETS-EXEC-20261011-v1"
c.operation == "metadata-apply-ccr"
c.execution_actor == "service:secrets-engine"
regex.match("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", c.operation_id)
c.ccr_id != c.execution_grant_ccr_id
hash_ok(c.ccr_immutable_sha256)
hash_ok(c.grant_immutable_sha256)
hash_ok(c.catalog_sha256)
hash_ok(c.expected_before)
hash_ok(c.expected_after)
c.backend_budget.ttl_seconds <= 120
c.backend_budget.ttl_seconds >= 30
c.backend_budget.uses == 12
count(c.operations) == 6
c.operations[0].method == "GET"
c.operations[1].method == "PUT"
c.operations[2].method == "GET"
c.operations[3].method == "GET"
c.operations[4].method == "PUT"
c.operations[5].method == "GET"
regex.match("^sys/policies/acl/[A-Za-z0-9_-]+$", c.operations[0].path)
regex.match("^auth/[A-Za-z0-9_-]+/role/[A-Za-z0-9_-]+$", c.operations[3].path)
c.operations[0].path == c.operations[1].path
c.operations[1].path == c.operations[2].path
c.operations[3].path == c.operations[4].path
c.operations[4].path == c.operations[5].path
every_operation_hash_valid
b := input.context.service_actor_binding
count(b) == 5
b.version == "proposed-service-task-caller/v1"
b.transport_principal == "system:serviceaccount:secrets-engine:secrets-engine"
b.subject_id == input.subject.id
b.subject_type == "service"
b.tenant == input.tenant
not input.context.task_execution_projection
not input.context.initiator
not input.context.represented_principal
not input.context.delegation
input.resource.attributes.stage == "prod"
time.parse_rfc3339_ns(c.operation_deadline) > time.now_ns()
time.parse_rfc3339_ns(c.operation_deadline) <= time.now_ns() + 120000000000
time.parse_rfc3339_ns(c.operation_deadline) >= time.now_ns() + (c.backend_budget.ttl_seconds + 5) * 1000000000
input.context.approval.schema_version == "0.1"
input.context.approval.kind == "approval-claim"
input.context.approval.issuer == "approval-engine"
input.context.approval.valid_now == true
input.context.approval.consumed == false
input.context.approval.reason_code == "ok"
input.context.approval.binding.pdp_path == true
hash_ok(input.context.approval.binding.pdp_digest)
time.parse_rfc3339_ns(input.context.approval.freshness.not_after) > time.now_ns()
time.parse_rfc3339_ns(input.context.approval.validity.expires_at) >= time.parse_rfc3339_ns(c.operation_deadline)
time.parse_rfc3339_ns(input.context.approval.freshness.not_after) >= time.parse_rfc3339_ns(c.operation_deadline)
input.context.approval.binding.human_control == true
}
every_operation_hash_valid {
count([x | x := input.context.execution_contract.operations[_]; hash_ok(x.payload_sha256)]) == 6
}
```
```rego test
import data.flexauth.secrets_engine.service_task_execution
test_unsigned_flags_cannot_enable {
service_task_execution.decision.effect == "deny"
with input as {"context": {"runtime_admission": true, "verified": true}}
}
```

View file

@ -0,0 +1,6 @@
# Synthetic source-validation fixture only; no estate registry admission.
resources:
- id: catalog:synthetic
system: secrets-engine
type: secret-catalog-lane
attributes: {stage: prod}