121 lines
4.9 KiB
Markdown
121 lines
4.9 KiB
Markdown
|
|
---
|
||
|
|
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}}
|
||
|
|
}
|
||
|
|
```
|