ADR 0048 — ZTP-Prem compliance enforcement (machine-readable contract)¶
- Status: Accepted (2026-05-14)
- Date: 2026-05-14
- Deciders: TLSStress.Art project (operator directive 2026-05-14)
- Builds on: ADR 0043 (OOBI VLAN), 0044 (intrusion), 0045 (Hello mesh), 0046 (Hello encryption), 0047 (VXLAN test payload only)
- Targets: v4.1.0+
Context¶
ZTP-Prem (Zero-Trust on Premises) was locked on 2026-05-11 as a 12-layer defence model against the insider-threat operator. Most of the cited layers exist piecewise in the codebase, but there is no machine-readable contract that says "this element implements this layer". Two consequences:
- Reviewers cannot tell, when accepting a new MÓDULO, whether it inherits the full ZTP-Prem perimeter.
- The operator cannot answer "where are we today?" with a single command — the posture is implicit in code instead of explicit in data.
The 2026-05-14 directive captured this explicitly:
Precisamos garantir que todos elementos, considerando elementos da Infra incluidos, modulos, kernel, runtimes, estejam conformes com a definição que tivemos sobre ZTP-Prem. Todos elementos do software devem estar protegidos contra insider threat bad actor.
Decision¶
Introduce a machine-readable compliance contract in pkg/oobi/ztp-compliance/:
The 12 layers (stable, ordered outermost → innermost)¶
| ID | Name | Summary | Source |
|---|---|---|---|
| L1 | Network boundary | TLS at every external surface + DSCP CS7 marking inside OOBI VLAN | ADR 0038 |
| L2 | Bearer-token L2 auth | OOBI_AUTH_TOKEN on every HTTP surface |
pkg/oobi/auth |
| L3 | L3 intrusion filter | Reject hosts outside /22, unknown slot, blacklisted |
ADR 0044 + pkg/oobi/intrusion |
| L4 | Encrypted Hello mesh | AES-256-GCM Hello over mcast+bcast | ADR 0045+0046 + pkg/oobi/hello |
| L5 | UTXO token vault | Chained-transaction token ledger; provable revocation | pkg/ztp-prem-signctl |
| L6 | Tier A/B code partition | Vendor-bypass primitives signed; operator can't redeploy Tier A | platform/ztp-prem/tier-policy.yaml |
| L7 | Confidential Computing | AMD SEV-SNP / Intel TDX VM enclave (v6.0+) | pkg/ztp-prem-tpm |
| L8 | Admission control | ValidatingAdmissionWebhook gates every pod creation | pkg/ztp-prem-admission |
| L9 | License enforcement | Offline JWT entitlement check | MÓDULO LICENSE.Art (planned) |
| L10 | Sealed audit chain | Append-only Merkle-chained log | ADR 0029 |
| L11 | Image signing | Sigstore/cosign + provenance verified at pull | — |
| L12 | Host hardening | seccomp/AppArmor + read-only root + CIS K8s | — |
Element categories + their expected layers¶
| Category | Members | Expected layers |
|---|---|---|
module |
15 first-party Go MÓDULOs (flow-art, api-infra-art, gateway-art, …, span-correlator) | L1, L2, L3, L4, L10, L12 |
infra-vendored |
postgres, grafana, prometheus | L1, L2, L3, L4 (via sidecar) |
infra-first-party |
dashboard (Next.js) | L1, L2, L3, L4 |
kernel |
kubelet, containerd, k3s control-plane | L7, L11, L12 |
runtime |
oobi-vlan-host-iface DaemonSet, customer-mgmt-vlan-host-iface | L1, L8, L9, L10 |
Layers outside an element's expected set return LayerStatusNotApplicable from the audit.
The audit pipeline¶
pkg/oobi/ztp-compliance/
├── layers.go 12-layer definitions, Registry of elements
├── audit.go Auditor interface + StaticAuditor + report rendering
├── cmd/ztp-audit/ CLI: `go run … ztp-audit [--json] [--exit-on-fail]`
Auditor is the extension point:
StaticAuditor(this PR) returns the build-time-asserted status. Fast, deterministic, offline. Used for CI gating + Dashboard rendering.KubernetesAuditor(next PR) probes live pods, Secrets, NetworkPolicies, image-digest signatures, host-kernel sysctls. Used for runtime compliance.
LayerStatus vocabulary¶
pass— implemented and verifiedfail— required but missing → blockingn/a— not applicable to this categorypending— known gap, scheduled (next wave)manual-verify— auditable only via human reviewinherit— inherited from host pod / sidecar
Summary classification¶
An element is Passing when no layer is in fail AND no expected layer is pending. The first pending demotes it to Pending. A single fail demotes it to Failing.
This rule is intentionally strict — pending is not pass. The dashboard summary shows three buckets, not two.
Current canonical baseline (2026-05-14)¶
Running ztp-audit against the canonical static auditor today:
- 24 elements total
- 0 failing — no element is in catastrophic gap
- 15 modules have L1–L4 = pass (post-v4.0.0 OOBI wave)
- 9 pending — vendored Infra (Postgres, Grafana, Prometheus) await PR-ZTP-2 sidecar; Dashboard awaits PR-ZTP-5 OOBI Bearer; kernel awaits L7+L11 wave
Consequences¶
Positive¶
- The compliance contract is now enforceable in code instead of carried in operator memory. CI can run
ztp-audit --exit-on-failto block PRs that introduce regressions. - The Dashboard ships a single page (
/admin/security/ztp-compliance, PR-ZTP-4) where the operator sees the full 24×12 matrix at a glance. - Adding a new MÓDULO that omits the Registry entry fails the audit silently by being missing — which is the desired behaviour for the next reviewer.
Negative¶
- Two-author bookkeeping:
pkg/oobi/canon.goslot map +Registry()must stay in sync. Mitigated by a CI test that asserts every canonical slot has a Registry entry (lands in PR-ZTP-4). - The 12 layers are an opinionated taxonomy. Future security-research could discover a 13th; we'll bump versions accordingly.
Neutral¶
- This PR ships only the framework + Static auditor. The KubernetesAuditor lives in a follow-up. Operators reading the audit today see "what the build claims" — runtime drift detection is the next iteration.
Rollout¶
| PR | Scope | State |
|---|---|---|
| PR-ZTP-1 (this PR) | pkg/oobi/ztp-compliance/ library + ztp-audit CLI + ADR 0048 |
in flight |
| PR-ZTP-2 | pkg/oobi-sidecar/ Go binary that wraps vendored Infra with L1-L4 |
next |
| PR-ZTP-3 | K8s sidecar injection for Postgres / Grafana / Prometheus | pending |
| PR-ZTP-4 | Dashboard /admin/security/ztp-compliance matrix view + API |
pending |
| PR-ZTP-5 | Dashboard Next.js endurecido com OOBI Bearer | pending |
References¶
- Memo:
project_ztp_prem_posture_locked_2026_05_11.md - ADR 0029 — sealed audit chain
- ADR 0043/0044/0045/0046/0047 — OOBI VLAN cluster
- Package:
pkg/oobi/ztp-compliance/