ADR-0006: enforcement is zone-scoped; defer the policy.enabled flip
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

flex-auth enforced its ops-warden pin (FLEX-WP-0016 T03) and the gate verified
clean against it: readiness exits 0, decision:f3f7c88f9585582a, anonymous
/v1/check now 401. Everything needed to set policy.enabled: true was in place.

It stays false, by decision. policy.enabled is a single repo-wide boolean, and
with fail_closed: true it makes flex-auth a hard dependency of every warden
sign — including the certs the ops-bridge tunnels depend on, one of which
carries the policy call itself. Uniform enforcement across an estate being
actively rebuilt hardens the access needed to perform the rebuild.

The repo already refuses one-dimensional posture: WP-0015 shipped environment
and maturity axes, WP-0029 added organization_posture. A global flag ignores all
three. ADR-0006 records that enforcement belongs to a zone, and binds future
work — a zone-blind enforcement flag is out of order, not merely unwise.

WARDEN-WP-0032 drafts the zone model, leading with the ownership question:
whether this is ops-warden's to own or NetKingdom canon to consume (ADR-0005).
WP-0031 is finished with T05 cancelled and resuming as WP-0032-T05.

Also replaces the hand-run kubectl port-forward with a managed ops-bridge
tunnel, flex-auth-ops-warden-railiance01 (-L 19090:10.43.1.165:8080).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-19 20:31:28 +02:00
parent 661176e37a
commit cbf6828061
7 changed files with 273 additions and 9 deletions

View file

@ -4,7 +4,7 @@ type: workplan
title: "Calling-side identity for flex-auth, so policy.enabled can flip"
domain: infotech
repo: ops-warden
status: active
status: finished
owner: ops-warden
topic_slug: netkingdom
planning_priority: P1
@ -139,7 +139,7 @@ Evidence: `history/2026-08-19-flex-auth-caller-identity-evidence.md`.
```task
id: WARDEN-WP-0031-T05
status: wait
status: cancel
priority: high
state_hub_task_id: "8b8e68c4-587d-490d-a98f-840aaff0fdb8"
```
@ -150,6 +150,21 @@ re-run the gate against the enforcing pin, and only then set
`policy.enabled: true` with `fail_closed: true`. Flipping before enforce buys
nothing; flipping before T04 401s every `warden sign`.
Asked flex-auth 2026-08-19 with the T04 evidence. Waiting on their enforce.
The closing `warden sign` also needs a scoped `VAULT_TOKEN` via
`ops-warden-warden-sign-token` (operator authenticates to OpenBao).
**Deferred 2026-08-19 under `ADR-0006`** — not blocked, decided against for now.
flex-auth did enforce (FLEX-WP-0016 T03, Helm rev 2): the pin runs
`--caller-auth-mode enforce`, the gate exits 0 against it
(`HTTP 200, effect=allow, decision:f3f7c88f9585582a`), and an anonymous
`/v1/check` is 401. Everything needed to flip was in place.
It was not flipped. `policy.enabled` is a single repo-wide boolean, and with
`fail_closed: true` it makes flex-auth a hard dependency of every `warden sign`
— including the certs the ops-bridge tunnels depend on, one of which carries
the policy call itself. Uniform enforcement across an estate being actively
rebuilt would harden the access needed to perform the rebuild. Enforcement
belongs to a zone, not to the repo; that is `ADR-0006`, and the model is
`WARDEN-WP-0032`. This task resumes as WARDEN-WP-0032-T05.
Also shipped while proving the flip: the gate URL is now a managed ops-bridge
tunnel `flex-auth-ops-warden-railiance01` (`-L 19090:10.43.1.165:8080`) instead
of a hand-run `kubectl port-forward`.

View file

@ -0,0 +1,123 @@
---
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.