From b845f4b51e871b914657ccdcfca4b2e09e7064e2 Mon Sep 17 00:00:00 2001 From: tegwick Date: Wed, 19 Aug 2026 20:38:25 +0200 Subject: [PATCH] =?UTF-8?q?Draft=20WARDEN-WP-0032=20properly=20=E2=80=94?= =?UTF-8?q?=20security=20zones,=20ownership=20question=20first?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expands the placeholder into a real plan, grounded in what the estate already has rather than first principles: - tenancy-posture_v0.1 is the structural model to follow (canon standard + per-repo declaration + "accuracy, not altitude"), and its §14 adoption stance is "structure, not tooling" — a precedent about sequencing. - Reefs are substrate placement zones with real risk statements. A security zone is not a reef; repo-manager's own "topology is not readiness" applies here as "placement is not posture". - flex-auth is latency-critical and already consumes a compiled registry snapshot, so zone membership should reach the PDP by compilation rather than a synchronous lookup in the decision path. - warden plan already returns verdicts with reasons; zone-aware enforcement extends that machinery instead of growing a parallel one. T01 settles ownership before any modelling, because it decides which repo the rest lives in: canon standard, a zone-engine runtime authority, or flex-auth policy data. The recommendation is canon-first with zone-engine named as an explicit promotion — but the time-boxed refactor exception is the case that could justify an engine immediately, since an expiring grant is state and state wants an owner. Co-Authored-By: Claude Opus 5 --- WORK-RECORDS.md | 10 +- workplans/WARDEN-WP-0032-security-zones.md | 233 +++++++++++++++------ 2 files changed, 180 insertions(+), 63 deletions(-) diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index fc678bb..41706d4 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -27,7 +27,8 @@ | workplan | WARDEN-WP-0028 | finished | — | workplans/WARDEN-WP-0028-tenant-secret-custody.md | | workplan | WARDEN-WP-0029 | finished | — | workplans/WARDEN-WP-0029-policy-front-door-and-founder-surface.md | | workplan | WARDEN-WP-0030 | finished | — | workplans/WARDEN-WP-0030-delegation-register.md | -| workplan | WARDEN-WP-0031 | active | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| workplan | WARDEN-WP-0031 | finished | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| workplan | WARDEN-WP-0032 | proposed | — | workplans/WARDEN-WP-0032-security-zones.md | | task | ADHOC-2026-06-27-T01 | done | — | workplans/ADHOC-2026-06-27.md | | task | ADHOC-2026-06-29-T01 | done | — | workplans/ADHOC-2026-06-29.md | | task | ADHOC-2026-08-11-T01 | done | — | workplans/ADHOC-2026-08-11.md | @@ -113,4 +114,9 @@ | task | WARDEN-WP-0031-T02 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | | task | WARDEN-WP-0031-T03 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | | task | WARDEN-WP-0031-T04 | done | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | -| task | WARDEN-WP-0031-T05 | wait | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| task | WARDEN-WP-0031-T05 | cancel | — | workplans/WARDEN-WP-0031-policy-caller-identity.md | +| task | WARDEN-WP-0032-T01 | todo | — | workplans/WARDEN-WP-0032-security-zones.md | +| task | WARDEN-WP-0032-T02 | todo | — | workplans/WARDEN-WP-0032-security-zones.md | +| 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 | diff --git a/workplans/WARDEN-WP-0032-security-zones.md b/workplans/WARDEN-WP-0032-security-zones.md index 441edf3..6d343fa 100644 --- a/workplans/WARDEN-WP-0032-security-zones.md +++ b/workplans/WARDEN-WP-0032-security-zones.md @@ -1,7 +1,7 @@ --- id: WARDEN-WP-0032 type: workplan -title: "Security zones — scope enforcement to bands of differing rigidity" +title: "Security zones — bands of enforcement rigidity, and where they live" domain: infotech repo: ops-warden status: proposed @@ -18,48 +18,103 @@ updated: "2026-08-19" # WARDEN-WP-0032 — Security zones -`ADR-0006` defers `policy.enabled: true` until enforcement can be scoped. This -workplan builds the thing it defers to. +`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. -## The problem in one paragraph +## The problem, precisely -ops-warden has three posture axes already: environment (`dev`/`test`/`prod`, -WP-0015), workload maturity (`M0`–`M3`, WP-0015), and organization posture -(`build`, WP-0029). What it does not have is a way to say *"this band of the -estate is enforced, that one is advisory"* — so every enforcement control it -ships is a repo-wide boolean. `policy.enabled` is the first one to actually -become flippable, and flipping it would harden the access needed to perform the -refactors currently underway. The axes describe posture; nothing acts on them. +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 a zone has to answer +| 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?** | -A zone is only useful if it decides something. Minimum: +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. -- **Membership** — what puts a lane, actor, or workload in this zone? Derived - from the existing axes where possible rather than a fourth hand-maintained - list. -- **Enforcement stance per control** — for each gate (pre-sign policy, agent - read-boundary, high-risk refusal): enforced, advisory, or exempt. -- **Failure mode** — fail-closed or fail-open, per control per zone. This is the - actual bite: `fail_closed` is what makes a dead tunnel an outage. -- **Who may change it, and how it is observed** — a zone that can be quietly - widened is not a boundary. +The three existing axes *describe*. Nothing *decides*. A zone is the object that +decides. -## Open questions to settle before designing +## What already exists — do not reinvent these -- Is a zone a property of the **actor** (`adm`/`agt`/`atm`), the **lane** - (catalog entry), the **workload**, or the **moment** (an active refactor)? The - CoulombCore decommission suggests the last one matters and is the hardest to - model — a time-boxed relaxation is a different object than a standing zone. -- Do zones compose with the three existing axes, or replace one? A fourth - independent axis multiplies states; folding `organization_posture` in may be - the honest move. -- Is this ops-warden's model to own at all, or NetKingdom canon that ops-warden - consumes? ADR-0005 says implement narrowly and route broadly. A security zone - model that only ops-warden honours is worth much less than one flex-auth, - secrets-engine, and tenant-engine also read — but ops-warden should not - absorb an estate-wide model on its own authority either. **Settle this - first**; it changes who writes the rest. +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 T02–T05 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. ## Tasks @@ -69,11 +124,15 @@ status: todo priority: high ``` -**Decide ownership before designing.** Take the third open question to -net-kingdom (canon) and flex-auth (the PDP that would enforce it). If it is -canon, ops-warden drafts and offers, as it did for the WP-0015 maturity model, -and consumes the result. If it is ops-warden's, say so explicitly and record -why. Do not build a model whose owner is unsettled. +**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. + +Deliverable: a decision record, and coordination messages sent. Do not model +anything before this closes. ```task id: WARDEN-WP-0032-T02 @@ -81,12 +140,24 @@ status: todo priority: high ``` -**Name the zones against reality, not in the abstract.** Walk the current -estate — the 27 catalog lanes, the actor inventory, the workloads with posture -descriptors — and see what bands actually exist. A zone model that does not -partition today's lanes cleanly is wrong, and the exceptions are the interesting -part. Include the refactor case explicitly: what zone is a lane in while the -component it fronts is being rebuilt? +**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. + +Must answer explicitly: + +- 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. ```task id: WARDEN-WP-0032-T03 @@ -94,22 +165,35 @@ status: todo priority: high ``` -**Model enforcement stance and failure mode per zone per control,** covering 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). Each must be expressible as enforced / advisory / -exempt with an explicit failure mode. +**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. ```task id: WARDEN-WP-0032-T04 status: todo -priority: medium +priority: high ``` -**Make `policy.enabled` zone-aware and retire the global boolean.** The -successor control reads the zone of the actor being signed for. Ship the -migration in the same change as the deprecation — leaving both is exactly the -second-source-of-truth failure ADR-0001 exists to prevent. +**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 @@ -117,7 +201,34 @@ status: todo priority: medium ``` -**Close WARDEN-WP-0031 T05 through this model** — enable the pre-sign gate for -whichever zone the SSH signing lane lands in, with that zone's failure mode. -Re-run `scripts/check_policy_caller_identity.py` first; the WP-0031 evidence -will be stale by then and re-establishing it is cheap by design. +**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. + +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. + +```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.