124 lines
4.7 KiB
Markdown
124 lines
4.7 KiB
Markdown
|
|
---
|
|||
|
|
id: WARDEN-WP-0032
|
|||
|
|
type: workplan
|
|||
|
|
title: "Security zones — scope enforcement to bands of differing rigidity"
|
|||
|
|
domain: infotech
|
|||
|
|
repo: ops-warden
|
|||
|
|
status: proposed
|
|||
|
|
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
|
|||
|
|
|
|||
|
|
`ADR-0006` defers `policy.enabled: true` until enforcement can be scoped. This
|
|||
|
|
workplan builds the thing it defers to.
|
|||
|
|
|
|||
|
|
## The problem in one paragraph
|
|||
|
|
|
|||
|
|
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.
|
|||
|
|
|
|||
|
|
## What a zone has to answer
|
|||
|
|
|
|||
|
|
A zone is only useful if it decides something. Minimum:
|
|||
|
|
|
|||
|
|
- **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.
|
|||
|
|
|
|||
|
|
## Open questions to settle before designing
|
|||
|
|
|
|||
|
|
- 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.
|
|||
|
|
|
|||
|
|
## Tasks
|
|||
|
|
|
|||
|
|
```task
|
|||
|
|
id: WARDEN-WP-0032-T01
|
|||
|
|
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.
|
|||
|
|
|
|||
|
|
```task
|
|||
|
|
id: WARDEN-WP-0032-T02
|
|||
|
|
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?
|
|||
|
|
|
|||
|
|
```task
|
|||
|
|
id: WARDEN-WP-0032-T03
|
|||
|
|
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.
|
|||
|
|
|
|||
|
|
```task
|
|||
|
|
id: WARDEN-WP-0032-T04
|
|||
|
|
status: todo
|
|||
|
|
priority: medium
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**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.
|
|||
|
|
|
|||
|
|
```task
|
|||
|
|
id: WARDEN-WP-0032-T05
|
|||
|
|
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.
|