Skip to content

Policy model

The policy model is a deterministic, typed evaluator with explicit predicates — not a scripting language and not embedded policy code. A policy states explicit requirements; the evaluator reports, per requirement, whether it is satisfied, violated, or unresolved, then combines those into one outcome.

A policy, concretely

apiVersion: xila-guard/v1alpha1
kind: PlacementPolicy
metadata:
  name: tenant-dedicated-baseline
spec:
  placementScope: node
  requirements:
    allowedRegions:
      - eu-central-1
    nodeTenantAssignment: sameTenant
    gpu:
      timeSlicing: forbidden
      mps: forbidden
      allowedPartitioning:
        - none
      approvedDriverVersions:
        - "fixture-driver-1"
      attestation: notRequired
  evidence:
    maxAgeSeconds: 60
    maxClockSkewSeconds: 5

fixture-driver-1 is synthetic

It is a test value, not a recommended driver. A real installation needs an operator-maintained approved set, and a successful check means version conformity, not absence of vulnerabilities.

Every enum, empty list, omitted optional field, and default has documented meaning. An empty allowlist matches nothing. Missing required fields make the policy invalid (a validation error, not a decision). An explicit notRequired means the predicate is simply not requested — it is not evidence that the property is satisfied.

Predicates

Predicate Status Notes
allowedRegions Supported Administrator assertion; empty list matches nothing
nodeTenantAssignment: sameTenant Supported Administrator assertion; needs resolved identity
gpu.timeSlicing: forbidden Supported Known true → deny; unknown → indeterminate
gpu.mps: forbidden Supported As above
gpu.allowedPartitioning Supported A separate dimension from time-slicing
gpu.approvedDriverVersions Supported Version conformity only, not vuln-free
evidence.maxAgeSeconds / maxClockSkewSeconds Supported Freshness + clock skew
gpu.attestation: required Recognized, satisfiable only via an accepted verifier With default (live) providers it is always indeterminate; enforcement blocks. See attestation

Decision outcomes

For every required predicate the evaluator computes satisfied, violated, or unresolved, then applies this algebra:

flowchart TD
    START[Evaluate every required predicate] --> V{any violated?}
    V -- yes --> DENY[deny<br/>exit 2]
    V -- no --> U{any unresolved?}
    U -- yes --> IND[indeterminate<br/>exit 3]
    U -- no --> ALLOW[allow<br/>exit 0]
  • deny if any required predicate is violated — unresolved findings are still preserved in the record.
  • indeterminate if none is violated but at least one is unresolved.
  • allow only if all required predicates are satisfied.

The enforcing adapter admits only allow. Unknown required fields, unsupported requirements, stale sources, partial device inventory, or mismatched node incarnations never default to allow. An invalid policy or request is a validation error, not a valid policy decision.

Monotonicity guarantee (property-tested)

Adding a requirement or removing required evidence can never turn a blocked result into allow. The same policy evaluated in enforce can differ from observe only by becoming more conservative (fewer accepted sources), never more permissive.

Effective requirements

Effective requirements are the conjunction of administrator policy and any allowed stricter workload requirements — a tenant can only tighten the baseline, never weaken it. Contradictory requirements produce an unsatisfiable result; they do not silently pick the more permissive value.

Reason codes

Each finding carries its policy field path, the expected requirement, the observed value / status, the source reference, and the candidate scope. Stable reason codes:

Reason code When
REGION_DISALLOWED Region outside the allowlist
TENANT_ASSIGNMENT_MISMATCH Node not assigned to the workload's tenant
TIME_SLICING_FORBIDDEN Time-slicing known enabled where forbidden
MPS_FORBIDDEN MPS known enabled where forbidden
PARTITIONING_DISALLOWED Partitioning value outside the allowlist
DRIVER_NOT_APPROVED Driver version known and not in the approved set
EVIDENCE_STALE Missing timestamp, older than maxAgeSeconds, or future-dated beyond skew
SOURCE_NOT_ACCEPTED Evidence source not accepted in this context (e.g. mock under enforce)
INVENTORY_INCOMPLETE Partial / mixed device inventory; cannot conclude
ATTESTATION_REQUIRED Attestation required but no accepted verifier result present
ATTESTATION_VERIFIER_NOT_ACCEPTED Verifier id not in acceptedAttestationVerifiers (e.g. sim:)
ATTESTATION_FAILED Appraised attestation outcome was fail
REQUIREMENT_UNSUPPORTED Predicate recognized but unsupported in this build
NODE_INCARNATION_MISMATCH Candidate node UID / incarnation ≠ snapshot
IDENTITY_UNRESOLVED Tenant could not be resolved
AUTHENTICATED_INVENTORY_MISSING require mode but no SVID-bound inventory for the node

Tenant-facing messages are sanitized so they never disclose another tenant's identity or placement.

Evidence sources

There is no universal numeric trust score. Acceptance is claim-specific and per-context. Every Observation<T> carries one of these source categories plus a source identity and times:

Source Meaning Accepted where
mock Administrator-controlled synthetic snapshot file Offline / observe only — rejected under enforce
admin_inventory Administrator assertion (e.g. GPU-operator sharing config) Node-authoritative config, not a hardware measurement
host_observation Read-only host query (e.g. bounded nvidia-smi) Discovery facts; never promoted to attestation
kubernetes_observation Facts observed from Kubernetes objects Observer context
authenticated_collector SVID-bound inventory from an mTLS collector Accepted under enforce (still rejects mock)
attestation_verifier Appraised result from an accepted RATS verifier Only source that can satisfy attestation: required

Observation status is one of known | unknown | unsupported | error. A known boolean false is distinct from all three non-known states — "we observed it is off" is not the same as "we don't know".

Fail-closed semantics

  • A missing collector, stale report, or unaccepted source never yields allow — there is no such code path.
  • Unavailable evidence produces indeterminate; enforce mode then blocks the new placement.
  • Freshness: a known observation is stale (→ EVIDENCE_STALE) if it has no timestamp, is older than maxAgeSeconds, or is future-dated beyond maxClockSkewSeconds. maxAgeSeconds: 0 disables the freshness check.
  • Node binding: the evaluator requires candidate.nodeUid == snapshot.nodeUid; a mismatch is NODE_INCARNATION_MISMATCH.
  • Policy digest is computed over a canonical JSON representation (recursively sorted keys), not raw YAML bytes. A decision expires no later than its earliest required-evidence expiry or the configured decision TTL; new policy / evidence revisions force re-evaluation sooner.

See the trust-sources ADR for the acceptance rules in full.