Hand the zone model to zone-engine; keep WP-0032 as the consumer side
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

zone-engine is seeded and owns the security zone model as ZONE-WP-0001. Under
ADR-0005 ops-warden implements one lane narrowly and routes the rest, and an
estate-wide enforcement model is not a lane to absorb — it was ops-warden's
deferred flip that exposed the gap, not ops-warden's model to define.

WARDEN-WP-0032 is rewritten as the consumer side: hand the estate inputs to
ZONE-WP-0001-T02 (27 catalog lanes, the actor inventory, the three posture axes,
the three controls the model must express, and the compiled-registry path),
then replace policy.enabled with a zone-aware control and amend ADR-0006 to say
ops-warden follows the model rather than owning it.

ADR-0006 and SCOPE updated to point at zone-engine, which joins the related
repositories table.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-19 21:20:34 +02:00
parent b845f4b51e
commit 8c58f8bfa1
4 changed files with 65 additions and 187 deletions

View file

@ -278,7 +278,7 @@ for the rest.
| WP | Status | Focus |
| --- | --- | --- |
| WP-0027 | `backlog` | Tamper-resistant credential governance + mass rotation/lockdown (Strand B follow-on to WP-0026) |
| WP-0032 | `proposed` | Security zones — scope enforcement to bands of differing rigidity (`ADR-0006`); unblocks the pre-sign gate |
| WP-0032 | `proposed` | Adopt security zones as a consumer — retire the global `policy.enabled` (model owned by `zone-engine`) |
| WP-0030 | `proposed` | Delegation register — record intended owner + blocker on every interim lane, `warden route gaps`, promotion gate |
Remaining production distance is also in other repos' lanes (see Known gaps).
@ -356,7 +356,7 @@ Remaining production distance is also in other repos' lanes (see Known gaps).
`callerAuth.mode: enforce` (FLEX-WP-0016) — the gate is **ready and verified**
(`decision:f3f7c88f9585582a`, anonymous `/v1/check` -> 401). `policy.enabled`
remains **false by decision**, not by blocker: `ADR-0006` scopes enforcement to
security zones, which WP-0032 defines. Re-check with
security zones, which `zone-engine` defines (`ZONE-WP-0001`). Re-check with
`scripts/check_policy_caller_identity.py`
- **Workload posture:** WP-0015 shipped (standard, descriptors, `warden policy`,
conformance checker, dev doubles); canon landing owner-driven
@ -439,6 +439,7 @@ Downstream: `ops-bridge` (primary), kaizen agents, CI automations, human operato
| `secrets-engine` | Owner-native secret-exec front door (`secrets-engine exec/route`); ops-warden routes provisioned secret lanes to it (WP-0019) and holds 6 more as interim proxies pending its front doors |
| `tenant-engine` | Intended owner of tenant/client secret front doors; ops-warden holds 3 tenant lanes as interim proxies (WP-0028 pattern, WP-0030 register) |
| `user-engine` | End-user identity/account lifecycle; no ops-warden lane today — route rather than absorb |
| `zone-engine` | Owns the security zone model and exception lifecycle (`ADR-0006`); ops-warden is its first consumer |
| `state-hub` | Workplan registry |
---

View file

@ -120,3 +120,4 @@
| task | WARDEN-WP-0032-T03 | todo | — | workplans/WARDEN-WP-0032-security-zones.md |
| task | WARDEN-WP-0032-T04 | todo | — | workplans/WARDEN-WP-0032-security-zones.md |
| task | WARDEN-WP-0032-T05 | todo | — | workplans/WARDEN-WP-0032-security-zones.md |
| task | WARDEN-WP-0032-T06 | todo | — | workplans/WARDEN-WP-0032-security-zones.md |

View file

@ -13,7 +13,7 @@ created: "2026-08-19"
updated: "2026-08-19"
last_reviewed: "2026-08-19"
review_interval: 6m
enforced_by: "warden.yaml policy.enabled; scripts/check_policy_caller_identity.py; WARDEN-WP-0032"
enforced_by: "warden.yaml policy.enabled; scripts/check_policy_caller_identity.py; zone-engine ZONE-WP-0001; WARDEN-WP-0032"
supersedes: ""
successor: ""
---
@ -61,7 +61,7 @@ does not enable a fail-closed authorization gate globally. Before
differing rigidity, each declaring what is enforced, what is advisory, and what
is exempt — and the gate must be scoped to them.
Concretely, until WARDEN-WP-0032 defines the zone model:
Concretely, until `zone-engine`'s `ZONE-WP-0001` defines the zone model:
- `policy.enabled` stays `false`. Its readiness is evidence, not a mandate.
- A gate that is *ready* is recorded as ready. Readiness is not a reason to
@ -94,7 +94,9 @@ the zone model rather than merged with a caveat in its description.
- `WARDEN-WP-0031` — the calling side that made the flip possible (T05 deferred
under this ADR)
- `WARDEN-WP-0032` — the zone model this record defers to
- `zone-engine` `ZONE-WP-0001` — the zone model this record defers to, seeded
2026-08-19 as the owning repo
- `WARDEN-WP-0032` — ops-warden's consumer-side adoption
- `wiki/WorkloadSecurityPosture.md` — the two axes already shipped (WP-0015)
- `wiki/PolicyGatedSigning.md` — the gate itself
- `history/2026-08-19-flex-auth-caller-identity-evidence.md` — readiness evidence

View file

@ -1,7 +1,7 @@
---
id: WARDEN-WP-0032
type: workplan
title: "Security zones — bands of enforcement rigidity, and where they live"
title: "Adopt security zones as a consumer — retire the global policy.enabled"
domain: infotech
repo: ops-warden
status: proposed
@ -9,112 +9,41 @@ owner: ops-warden
topic_slug: netkingdom
planning_priority: P1
depends_on_workplans:
- WARDEN-WP-0015
- WARDEN-WP-0029
- WARDEN-WP-0031
created: "2026-08-19"
updated: "2026-08-19"
---
# WARDEN-WP-0032 — Security zones
# WARDEN-WP-0032 — Adopt security zones as a consumer
`ADR-0006` defers `policy.enabled: true` until enforcement can be scoped to a
zone. This workplan builds the model it defers to, and — first — settles who
owns it.
zone. **The zone model itself is no longer ops-warden's work.** It moved to
`zone-engine` as `ZONE-WP-0001` on 2026-08-19, where it belongs under `ADR-0005`
— ops-warden implements one lane narrowly and routes the rest, and an
estate-wide enforcement model is not a lane it should absorb.
## The problem, precisely
What stays here is the consumer side: ops-warden was the repo whose deferred
flip exposed the gap, it holds the controls the model must be able to express,
and it is the first consumer the model has to satisfy.
ops-warden can express *how exposed* something is and *how mature* it is. It
cannot express *how rigidly this band of the estate is governed right now*.
## What ops-warden owes zone-engine
| Axis | Shipped | Answers |
| --- | --- | --- |
| Environment posture (`dev`/`test`/`prod`) | WP-0015 | Where does this run? |
| Workload maturity (`M0``M3`) | WP-0015 | How ready is this workload? |
| `organization_posture: build` | WP-0029 | What state is the org in? |
| **Enforcement stance** | **missing** | **Is this control enforced here, and what happens when it fails?** |
Inputs, not designs. `ZONE-WP-0001-T02` derives the model from the real estate,
and most of that estate is ops-warden's:
Because the fourth is missing, every enforcement control ops-warden ships is a
repo-wide boolean. `policy.enabled` is the first to become flippable, and
flipping it would make flex-auth a hard dependency of every `warden sign`
including the certificates the ops-bridge tunnels depend on, one of which
carries the policy call itself. Across an estate mid-refactor that hardens
exactly the access needed to perform the refactor.
The three existing axes *describe*. Nothing *decides*. A zone is the object that
decides.
## What already exists — do not reinvent these
Four estate mechanisms are adjacent, and getting the relationships right is most
of the design work.
**`net-kingdom/canon/standards/tenancy-posture_v0.1.md`** — the closest
structural analogue and the model to follow: six orthogonal axes, graduated
levels, a per-repo declaration file (`tenancy.yaml`) carrying current /
implemented / target vectors with evidence and a review date, and §6
"conformance is accuracy, not altitude". Its §14 adoption stance is
*"structure, not tooling"* — a direct precedent about sequencing, and one this
workplan should not quietly break.
**Reefs** (`repo-manager/docs/RailianceAppDeploymentGuide.md`) — `reef-railiance`,
`reef-storage`, named in a rapp's `bound_reefs`. These are **substrate**
placement zones with real risk statements attached (`reef-railiance` carries a
single-node/shared-control-plane residual risk requiring explicit acceptance).
A security zone is *not* a reef — reef answers *where does it run*, zone answers
*how rigidly is it governed* — but they are correlated, and a taxonomy that
ignores reefs will fight them. Also note repo-manager's own ADR-0006: *topology
is not readiness*. The same caution applies here: **placement is not posture.**
**flex-auth** — the PDP, `service_class: latency-critical`, which already
consumes a *compiled registry snapshot*
(`registry/flex-auth/production_registry_snapshot.json`, built by
`scripts/build_flex_auth_registry.py`). This matters enormously for T03: zone
membership can reach the decision point by compilation, with no runtime lookup
and no new service in the request path.
**`warden plan`** (WP-0029) — already classifies a need as `autonomous` /
`founder_required` / `unroutable` from properties of the thing, returning the
`reasons` that produced the verdict. Zone-aware enforcement should extend this
verdict machinery rather than grow a parallel one.
## The question that changes everything else: who owns this?
Three placements are defensible. **T01 settles it before any modelling**,
because the answer changes who writes T02T05 and in which repo they live.
**(a) NetKingdom canon + per-repo declaration.** A `security-zones_v0.1.md`
standard beside `tenancy-posture_v0.1.md`; each repo declares its lanes'
zones in a `zones.yaml` the way it already declares `tenancy.yaml`; flex-auth
enforces from the compiled registry. ops-warden drafts and offers, exactly as it
did for the WP-0015 maturity model. *Strongest fit to precedent; no new runtime
dependency; matches "structure, not tooling".*
**(b) A new `zone-engine` repo.** A runtime authority owning zone identity,
membership, and lifecycle, in the family of `tenant-engine` / `user-engine` /
`secrets-engine` — each of which has a boundary contract in canon. *Justified
if and only if zone membership needs minting, an API other components query, or
— the real candidate — **time-boxed exceptions with expiry and an audit trail of
who widened what**. A standing classification does not need an engine; a
relaxation that must expire probably does.*
**(c) flex-auth policy data.** Zones as attributes in the policy package, no new
artefact anywhere. *Cheapest, and wrong if zones must govern controls flex-auth
does not evaluate — the agent read-boundary (ADR-0004) and `warden desk`
escalation are ops-warden-side and would fall outside.*
**Recommendation to be tested in T01, not assumed:** start at (a), and name
(b) as an explicit promotion with a written trigger, rather than seeding an
engine before the model exists. An empty `zone-engine` would end up defining
zones by accident — through whatever its first schema happened to be — which is
the failure `ADR-0001` names in a different register. The counter-argument
deserves a fair hearing: if time-boxed refactor exceptions are in scope from day
one, (b) may be right immediately, because an expiring grant is state and state
wants an owner.
Under `ADR-0005` ops-warden does not absorb an estate-wide model on its own
authority. A zone model only ops-warden honours is worth much less than one
flex-auth enforces and secrets-engine reads.
- **27 routing catalog lanes** (`registry/routing/catalog.yaml`) with `risk`,
`status`, and `delegation` already on each — the likeliest membership inputs.
- **The actor inventory** (`adm` / `agt` / `atm`) and its TTL policy.
- **The three posture axes already shipped** — environment and maturity
(WP-0015), `organization_posture` (WP-0029) — including the honest answer to
whether `organization_posture` should be folded into zones rather than run
beside them.
- **Three controls the model must be able to express**: the flex-auth pre-sign
gate (`policy.enabled` + `fail_closed`), the agent read-boundary on
`risk: high` lanes (`ADR-0004`), and the `warden plan` escalation verdicts.
- **The compiled-registry path** (`scripts/build_flex_auth_registry.py`) — how
membership can reach flex-auth without a lookup in a latency-critical decision
path.
## Tasks
@ -124,111 +53,56 @@ status: todo
priority: high
```
**Settle ownership and placement.** Take the three options above to
`net-kingdom` (canon) and `flex-auth` (the PDP that would enforce), with the
time-boxed-exception question stated explicitly since it is what decides
between (a) and (b). Record the outcome as a decision with its reasoning — if
it lands outside ops-warden, this workplan's remaining tasks move to the owning
repo and ops-warden keeps only its consumer-side tasks.
**Hand the estate inputs to `ZONE-WP-0001-T02`.** Not a design proposal — the
lanes, actors, axes, and controls above, with the exceptions ops-warden already
knows do not fit cleanly (the interim delegation lanes from WP-0030 are the
obvious candidates: a lane covered on someone else's behalf may not sit in the
same zone as one ops-warden owns outright).
Deliverable: a decision record, and coordination messages sent. Do not model
anything before this closes.
Include the `organization_posture` fold-in question honestly, including the case
against keeping it.
```task
id: WARDEN-WP-0032-T02
status: todo
status: wait
priority: high
```
**Derive the zones from the real estate, not from first principles.** Walk the
27 catalog lanes, the actor inventory (`adm`/`agt`/`atm`), and the workloads
carrying posture descriptors, and find the bands that actually exist. The test
of the model is that it partitions today's estate without a residue of
exceptions; the exceptions found are the most informative output.
**Replace `policy.enabled` with a zone-aware control.** Waits on
`ZONE-WP-0001-T03` and `T05`. Reads the zone of the actor being signed for and
that zone's failure mode. Ship deprecation and migration in the same change —
leaving both is the second-source-of-truth failure `ADR-0001` exists to prevent.
Must answer explicitly:
Re-run `scripts/check_policy_caller_identity.py` before enabling anything: the
WP-0031 evidence (`decision:f3f7c88f9585582a`, 2026-08-19) will be stale, and
re-establishing it is cheap precisely so this is a re-check rather than a re-do.
- Is a zone a property of the **actor**, the **lane**, the **workload**, or the
**moment**? The CoulombCore decommission shows the last one is real and is the
hardest to model — a time-boxed relaxation is a different object from a
standing zone, and conflating them produces a permanent hole with a
temporary-sounding name.
- Do zones **compose with or fold in** the three existing axes? A fourth
independent axis multiplies states; absorbing `organization_posture` may be
the honest move.
- How do zones relate to **reefs**? Correlated, not identical. Say so in the
model rather than leaving readers to assume either.
This closes `WARDEN-WP-0031-T05`.
```task
id: WARDEN-WP-0032-T03
status: todo
priority: high
status: wait
priority: medium
```
**Model stance and failure mode per zone per control.** For each control:
enforced / advisory / exempt, *and* fail-closed or fail-open. The failure mode
is the part with teeth — `fail_closed` is what turns a dead tunnel into an
outage, and it is the reason `policy.enabled` was deferred.
Controls in scope at minimum: the flex-auth pre-sign gate (`policy.enabled`,
`fail_closed`), the agent read-boundary on `risk: high` lanes (`ADR-0004`), and
the `warden plan` escalation verdicts (WP-0029).
Prefer **compilation over runtime lookup** for anything flex-auth evaluates: it
is latency-critical and already consumes a built registry snapshot. Adding a
synchronous zone lookup to the decision path would be a regression dressed as an
architecture.
**Declare ops-warden's zones** in whatever format `ZONE-WP-0001-T05` settles,
alongside the existing posture descriptors. Carry the conformance rule:
*accuracy, not altitude*. Declaring a stricter zone than can be evidenced is the
failure mode that looks like progress.
```task
id: WARDEN-WP-0032-T04
status: todo
priority: high
```
**Declaration format and conformance rule.** Follow `tenancy.yaml`: a per-repo
declaration, with evidence, a `reviewed` date and a `review_due`, and the §6
rule carried over — **accuracy, not altitude**. A repo declaring a stricter zone
than it can evidence is the failure mode to design against, because it is the
one that looks like progress.
Include how a zone assignment is *changed*, and how that change is observed. A
zone that can be quietly widened is not a boundary. If time-boxed exceptions
exist, their expiry must be enforced by something, not by an intention.
```task
id: WARDEN-WP-0032-T05
status: todo
status: wait
priority: medium
```
**Make `policy.enabled` zone-aware and retire the global boolean.** The
successor control reads the zone of the actor being signed for and that zone's
failure mode. Ship deprecation and migration in the same change — leaving both
is the second-source-of-truth failure `ADR-0001` exists to prevent.
**Amend `ADR-0006`.** Once zones exist and enforcement scoping is owned by
`zone-engine`, ADR-0006 must say that ops-warden *follows* the model rather than
owning it — a superseding record, never an in-place edit. Update `SCOPE.md`,
`wiki/WorkloadSecurityPosture.md`, and `wiki/PolicyGatedSigning.md` with it.
This closes `WARDEN-WP-0031-T05`, cancelled under `ADR-0006`. Re-run
`scripts/check_policy_caller_identity.py` first: the WP-0031 evidence
(`decision:f3f7c88f9585582a`, 2026-08-19) will be stale, and re-establishing it
is cheap precisely so this is a re-check rather than a re-do.
## Related
```task
id: WARDEN-WP-0032-T06
status: todo
priority: medium
```
**Close out honestly.** Update `SCOPE.md`, `wiki/WorkloadSecurityPosture.md`,
and `wiki/PolicyGatedSigning.md`. If the model landed in canon or in another
repo, `ADR-0006` gains a successor or an amendment recording where enforcement
scoping now lives — ops-warden follows it rather than owning it, and the ADR
must say which.
## Deliberately out of scope
- **Network segmentation.** "Zone" is an overloaded word; this model is about
*enforcement rigidity*, not routing or NetworkPolicy. Say so wherever the term
first appears, or the two will be conflated within a quarter.
- **Re-litigating the three existing axes.** They stay as they are unless T02
finds a fold-in.
- **Zones for anything ops-warden does not consume**, unless T01 hands the model
to an owner who needs the wider scope.
- `zone-engine` `ZONE-WP-0001` — the model, and where this work is led from
- `ADR-0006` — enforcement is zone-scoped, never a global flag
- `WARDEN-WP-0031` — the deferred flip and its readiness evidence