Complete security zone model and canon draft

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0291a-1e87-7151-9934-fcbfe3f65eb1
This commit is contained in:
tegwick 2026-08-22 14:03:46 +02:00
parent 14f789d080
commit b7095bbabd
5 changed files with 346 additions and 25 deletions

View file

@ -63,8 +63,12 @@ remembering to collect a signature."* Decision 5.6 then ruled that stance
A classification that changes nothing is a label. A zone earns its keep only if
it decides something, so the model must carry:
- **Membership** — what puts a lane, actor or workload in a zone, derived from
posture already declared rather than a fourth hand-maintained list.
- **Identity and membership** — an authoritative workload binding and its
responsible party's declared zone. Lanes, actors, paths and repositories are
inputs or caller context, never substitute policy subjects.
- **Admission** — a mechanical reconciliation of that declaration against the
zone floor and the workload posture. Missing identity, membership or evidence
remains `unknown`; it is never inferred into a permissive zone.
- **Stance per control** — enforced, advisory, or exempt.
- **Failure mode** — what happens when the control cannot run. This is where
the bite is; `fail_closed` is what turns a dead tunnel into an outage.

View file

@ -130,15 +130,17 @@ Their answers are binding on this repo and are recorded in the workplan.
## Current state (2026-08-22)
`ZONE-WP-0001` is active. T01 confirmed ownership, T02 partitioned the estate,
and T04 selected reviewed declarations with enforcement-time expiry: **no
zone-engine runtime is warranted**. The exception lifecycle is recorded in
`docs/exception-lifecycle-2026-08-22.md`.
`ZONE-WP-0001` is active. T01T05 are complete: ownership is confirmed, the
estate is partitioned, stance and failure mode are modelled, the exception
lifecycle requires **no zone-engine runtime**, and the declaration/compiler
contract is drafted. The integrated owner draft is
`docs/security-zones_v0.1.md`.
T03 is waiting on a declaration-boundary ruling from `repo-manager` and
`net-kingdom`. The current evidence has nine declared rapp workloads, but only
one of ops-warden's 27 lanes can be joined to one; unknown membership is kept
unknown rather than inferred. No API, storage, or wire schema has been shipped.
Net-kingdom Decisions 5.6.1 and 5.6.2 settle the workload boundary. Operational
execution units declare authoritative workload identity directly in
`tenancy.yaml`; absence resolves to `unknown`, never inference. T06 is offering
the draft for canon publication and T07 remains adoption. No API, storage, or
wire schema has been shipped.
---

View file

@ -11,8 +11,8 @@
| workplan | ZONE-WP-0001 | active | — | workplans/ZONE-WP-0001-security-zone-model.md |
| task | ZONE-WP-0001-T01 | done | — | workplans/ZONE-WP-0001-security-zone-model.md |
| task | ZONE-WP-0001-T02 | done | — | workplans/ZONE-WP-0001-security-zone-model.md |
| task | ZONE-WP-0001-T03 | wait | — | workplans/ZONE-WP-0001-security-zone-model.md |
| task | ZONE-WP-0001-T03 | done | — | workplans/ZONE-WP-0001-security-zone-model.md |
| task | ZONE-WP-0001-T04 | done | — | workplans/ZONE-WP-0001-security-zone-model.md |
| task | ZONE-WP-0001-T05 | todo | — | workplans/ZONE-WP-0001-security-zone-model.md |
| task | ZONE-WP-0001-T06 | todo | — | workplans/ZONE-WP-0001-security-zone-model.md |
| task | ZONE-WP-0001-T05 | done | — | workplans/ZONE-WP-0001-security-zone-model.md |
| task | ZONE-WP-0001-T06 | progress | — | workplans/ZONE-WP-0001-security-zone-model.md |
| task | ZONE-WP-0001-T07 | todo | — | workplans/ZONE-WP-0001-security-zone-model.md |

290
docs/security-zones_v0.1.md Normal file
View file

@ -0,0 +1,290 @@
---
id: security-zones_v0.1
type: standard
status: draft
owner: zone-engine
publication_owner: net-kingdom
date: "2026-08-22"
---
# NetKingdom Security Zones v0.1
## 1. Purpose
A security zone is a named workload-admission standard. It answers which
scrutiny a workload has qualified for; control-owner policy then answers what a
particular control does in that zone. A zone is not a repository label, a
credential lane, a network segment, a reef, or a temporary exception.
This standard is a sibling of `tenancy-posture_v0.1`. It owns zone identity,
membership, admission, resolution, and the time-boxed exception lifecycle.
`flex-auth` remains the only PDP for decisions it renders. Every other control
continues to be owned and evaluated at its existing enforcement point.
## 2. Authority and conformance
Authority is split deliberately:
| Fact or rule | Authority |
| --- | --- |
| Workload identity and requested membership | Workload's responsible repo |
| Zone identities and admission standards | This standard, owned by zone-engine |
| Per-zone stance | Owner of the control that renders the effect |
| Failure behavior when a dependency is unavailable | Owner of the PEP |
| Publication | net-kingdom canon |
Conformance is **accuracy, not altitude**. A lower zone declared with evidence
is conformant. A stricter zone that the workload cannot evidence is not.
Changing membership to evade a control is not an exception mechanism.
The workload is the sole policy subject. It includes independently governed
application, automation, maintenance, and operational/control-plane execution
units. SSH access, tunnel operation, credential brokering, policy machinery,
and maintenance work therefore require workload identities even when they have
no `rapp`. Human and agent identities remain caller context and cannot be the
sole workload binding.
## 3. Resolution is authoritative
The stable `workload_identity.name` is the join key. Runtime principals,
resources, credential lanes, and controls reference it explicitly. A resolver
MUST NOT infer membership from repository ownership, paths, lane types, actor
classes, environment, criticality, reefs, organization posture, or naming
conventions.
Resolution returns both the declaration and its admission result:
- `satisfied` — the workload has an authoritative identity and evidence meeting
the declared zone's floor; `effective_zone` is the declared zone;
- `unsatisfied` — identity and membership are declared, but evidence is below
the admission floor; `effective_zone` is `unknown`;
- `unknown` — identity, membership, or a required floor/evidence input cannot be
resolved; `effective_zone` is `unknown`.
`unknown` is a result, not a zone. A control MUST declare an explicit treatment
for it. That treatment may deny, escalate, or use a reviewed build-stage rule;
it never manufactures membership and never grants an exception.
## 4. Zone catalog
The initial catalog follows the estate's existing `M0``M3` maturity ladder and
adds one non-monotone continuity band required by ops-warden `ADR-0006`.
| Zone id | Admission floor | Environment/data boundary | Purpose |
| --- | --- | --- | --- |
| `z0-experimental` | `M0` promotion evidence | Synthetic only; no real credential or user data | Experiments where advisory controls preserve iteration speed |
| `z1-operational` | `M1` promotion evidence | Production secret handling for at most `internal` data | Early operational workloads with an owned front door |
| `z2-protected` | `M2` promotion evidence | `prod`; at most `confidential` data | Production workloads requiring review, SLO/on-call, and incident readiness |
| `z3-critical` | `M3` promotion evidence | `prod`; at most `restricted` data | Critical or regulated workloads with the strongest normal failure behavior |
| `z3-continuity` | `M3` plus dependency/recovery evidence | `prod`; at most `restricted` data | Foundational access or recovery workloads where fail-closed dependency cycles would cause an outage |
`z3-continuity` is a sibling of `z3-critical`, not a lower rung. It exists
because enforcement stance is not monotone: a tunnel or credential-issuance
path can require M3 scrutiny while deliberately remaining fail-open for one
availability-sensitive control. Placement on a reef is never evidence for any
zone.
### 4.1 Context floor
The declared zone must be at least as strict as the workload context requires.
The context floor is the maximum of every resolved input:
| `criticality` | Minimum maturity |
| --- | --- |
| `low` | `M0` |
| `medium` | `M1` |
| `high` | `M2` |
| `critical` | `M3` |
Data-class floors are consumed from the canon-owned classification mapping; the
current `synthetic → M0`, `internal → M1`, `confidential → M2`, and
`restricted → M3` mapping is already used by ops-warden. An absent or unresolved
floor makes admission `unknown`. In particular, `public` is disclosure policy
and `synthetic` is data origin: they are not aliases, and this standard does not
invent a floor while info-tech-canon's ruling is pending.
`organization_posture` may select a versioned control profile, but it never
changes identity, membership, or admission.
## 5. Stance and failure-mode model
Every owner-qualified control publishes a total mapping over all zone ids plus
`unknown`. There is no implicit default.
- `enforced` — the control's deny or escalation effect changes the outcome;
- `advisory` — the control evaluates fully and records the outcome it would
have produced, but does not block;
- `exempt` — the control is deliberately not evaluated for this zone and emits
the versioned exemption reason.
Failure mode is separate and PEP-side:
- `fail_closed` — an unavailable or invalid evaluator produces the control's
safe blocking/escalation outcome;
- `fail_open` — the PEP proceeds and records that the control was unavailable.
`exempt` has no failure mode. A local control with no remote dependency uses
`fail_closed` to describe evaluator errors. Changing stance is a policy-package
change owned by the control owner, not a membership change.
### 5.1 Initial build-stage control profile
This profile is the v0.1 proposal for the first consumer. It is not stored in a
workload's `zones:` declaration. flex-auth owns the pre-sign rows; ops-warden
owns the other rows and every PEP failure mode.
| Zone | flex-auth pre-sign stance / ops-warden PEP | agent high-risk read boundary | `warden plan` zone rule |
| --- | --- | --- | --- |
| `z0-experimental` | `advisory` / `fail_open` | `enforced` / `fail_closed` | `advisory`; evaluator failure cannot produce `autonomous` |
| `z1-operational` | `advisory` / `fail_open` | `enforced` / `fail_closed` | `advisory`; evaluator failure cannot produce `autonomous` |
| `z2-protected` | `enforced` / `fail_open` | `enforced` / `fail_closed` | `enforced`; minimum `founder_required` when the zone rule matches |
| `z3-critical` | `enforced` / `fail_closed` | `enforced` / `fail_closed` | `enforced`; minimum `founder_required` when the zone rule matches |
| `z3-continuity` | `enforced` / `fail_open` | `enforced` / `fail_closed` | `enforced`; minimum `founder_required` when the zone rule matches |
| `unknown` | `advisory` / `fail_open` under the versioned `build` profile | `enforced` / `fail_closed` | `enforced`; never `autonomous` from zone evidence |
The `unknown` pre-sign treatment is an explicit organization-build policy, not
a permissive membership default. It must change through a versioned control
profile when the organization posture graduates.
The agent read boundary stays enforced in every zone: build-stage permissiveness
does not extend to disclosing high-risk credentials. For a missing lane risk:
- `z0-experimental` may resolve to `standard` only when admission proves the
lane can expose synthetic material exclusively;
- `z1-operational` and `z2-protected` resolve to at least `high`;
- `z3-critical` and `z3-continuity` resolve to `critical`, treated by the
boundary as at least `high`; and
- unresolved membership resolves to at least `high`.
An explicit grade always remains preferable. `accepted` is an acceptance record,
not a risk grade.
## 6. Declaration in `tenancy.yaml`
For a single-service declaration, `zones:` is a sibling of `tenancy:` and
`workload_identity`. For a `services:` declaration, both `workload_identity` and
`zones` occur inside the same service entry. A multi-service file MUST NOT use a
top-level `zones:` block.
```yaml
schema_version: "0.1"
framework: netkingdom-tenancy-posture
service: ops-bridge-tunnel
role: operational-access-path
workload_identity:
name: ops-bridge-tunnel
kind: operational-control-plane
responsible_repo: ops-bridge
identity_bindings:
- scheme: ssh-certificate
authority: ops-warden
subject: agt-ops-bridge
principal_type: agent
environment: prod
tenancy:
# tenancy-posture_v0.1 content omitted
zones:
standard: security-zones_v0.1
membership: z3-continuity
responsible_party: ops-bridge
justification: foundational tunnel path must retain availability under PDP loss
evidence:
- ref: docs/evidence/ops-bridge-tunnel-zone.md
supports: [M3, continuity-dependency, recovery]
reviewed: "2026-08-22"
review_due: "2026-11-22"
```
The `zones:` block contains only membership evidence. It MUST NOT contain
control stance, failure mode, organization posture, or exceptions.
Required fields are:
- `standard` — exactly `security-zones_v0.1`;
- `membership` — one zone id from §4;
- `responsible_party` — the party answering for this membership;
- `justification` — why the zone fits the workload's actual context;
- `evidence` — one or more references and the admission facts each supports;
- `reviewed` and `review_due` — ISO dates, with review due after review.
Permanent membership changes are reviewed source changes. A change to a lower
floor also records its reason and approver in the change review. Temporary
relaxation uses an exception and never changes `membership`.
## 7. Compilation and resolved view
Compilation produces a workload-addressable resolved record. At minimum it
contains:
```yaml
workload_id: ops-bridge-tunnel
identity_binding: ssh-certificate/ops-warden/agt-ops-bridge
declared_zone: z3-continuity
admission: satisfied
effective_zone: z3-continuity
membership_revision: sha256:<digest>
guarantees:
- authoritative-workload-identity
- explicit-zone-membership
- non-inferred-resolution
- enforcement-time-exception-expiry
controls:
- id: flex-auth/pre-sign
policy_owner: flex-auth
stance: enforced
pep_owner: ops-warden
failure_mode: fail_open
policy_ref: <versioned-package>
```
The `membership_revision` covers the authoritative workload binding, `zones:`
block, and source revision. Control results include their policy/profile version
and any active exception id and expiry. This is the machine-readable answer to
“which zone is this workload in, and what applies there?” It may be compiled
into existing consumer artifacts; it is not a synchronous zone-engine lookup.
For flex-auth's pre-sign control, the governed workload is the target of the
certificate or grant, so the compiler writes `workload_id`, `security_zone`,
`security_zone_admission`, and `security_zone_revision` on the resource
attributes. Caller identity remains in the subject. A control that governs the
requesting workload must declare that role explicitly and use separately named
caller-workload attributes.
The dormant `trust_zone: platform` constant is not security-zone membership and
MUST be retired before adoption. The new concept is named `security_zone`; the
two fields must not coexist as competing zone sources.
## 8. Membership-change observability
A membership change becomes effective only through a reviewed declaration and
a newly compiled artifact. The compiler emits the source and membership
revision, rejects ambiguous identities, and reports additions, removals, and
changes against the preceding snapshot. Controls expose the membership revision
in their decision or verdict evidence.
A zone that can be widened by editing an unversioned runtime label is not
conformant.
## 9. Time-boxed exceptions
The normative lifecycle is the T04 decision in
`docs/exception-lifecycle-2026-08-22.md`: only the control owner's designated
authority grants a named-workload, named-zone, named-control relaxation within a
declared maximum duration. Enforcement applies it only for
`not_before <= now < not_after`; invalid or unevaluable records are inactive,
expiry restores the base rule automatically, and no minted credential, lease,
or session may outlive the exception.
Exceptions live with the versioned control policy or PEP configuration and are
evaluated where their effects occur. This requires no zone-engine runtime.
## 10. Adoption
The draft is offered to net-kingdom for publication. Adoption requires:
1. flex-auth and ops-warden accept the initial control profile or publish a
versioned replacement with total zone and `unknown` coverage;
2. at least two workload owners declare authoritative identities and zones;
3. a third consumer compiles or reads the resolved view; and
4. ops-warden retires `policy.enabled` and the dormant `trust_zone` constant in
the same migration.

View file

@ -269,7 +269,7 @@ those lanes are graded.
```task
id: ZONE-WP-0001-T03
status: wait
status: done
priority: high
state_hub_task_id: "7f47b750-1ae4-467d-b3c4-064f4ec07dbd"
```
@ -283,18 +283,24 @@ Controls in scope at minimum: the flex-auth pre-sign gate (`policy.enabled`,
`fail_closed`), the agent read-boundary on `risk: high` lanes (ops-warden
`ADR-0004`), and the `warden plan` escalation verdicts.
**Waiting on owner rulings, 2026-08-22.** Re-running
**Owner rulings arrived and task completed, 2026-08-22.** Re-running
`ops-warden/scripts/report_workload_join.py` finds **nine** declared rapp
workloads, but still only **one of 27 lanes** joins to a workload; 13 name an
undeclared candidate and 13 have no workload-shaped path. The exact residue was
sent to `repo-manager` (declaration ownership/surface) and `net-kingdom`
(whether operational control-plane consumers must acquire workload identities,
and whether unknown is a required result). This is the consultation required by
the 2026-08-20 finding below; stance modelling will not reopen the policy subject
merely to make the corpus fit. In the interim, `RISK-N-0004`'s consumer
requirements are accepted: the resolved view is workload-addressable,
undeclared candidate and 13 have no workload-shaped path. Net-kingdom Decisions
5.6.1 and 5.6.2 settle the residue: operational/control-plane execution units
are workloads; non-rapp workloads declare authoritative identity directly in
`tenancy.yaml`; the stable workload id is the explicit join key; and absent
identity, membership, or floor resolves to `unknown` without inference. Canon's
schema now requires `workload_identity` beside every `zones:` block, which also
settles the declaration surface originally asked of `repo-manager`.
The stance, failure-mode, maturity-derived default, and initial control profile
are defined in `docs/security-zones_v0.1.md` §§45. `RISK-N-0004`'s consumer
requirements are carried into §7's resolved view: it is workload-addressable,
authoritative, machine-readable, exposes guarantees as well as membership, and
returns unknown without inference.
returns `unknown` without manufacturing a zone. The unresolved `public`
DataClassification floor is handled honestly as `unknown` pending
info-tech-canon's ruling; it no longer blocks the model.
**Operator direction 2026-08-19 — defaults derive from maturity, not from
nothing.** An ungraded lane must not inherit the safest-for-the-tool default; it
@ -553,7 +559,7 @@ cheaper outcome, but it is T04's call.
```task
id: ZONE-WP-0001-T05
status: todo
status: done
priority: medium
state_hub_task_id: "f4556ca0-cb26-46ed-9351-d00270bd2309"
```
@ -563,6 +569,19 @@ with evidence, `reviewed`, and `review_due`; carry over *accuracy, not
altitude*. Include how a zone assignment changes and how that change is
observed — a zone that can be quietly widened is not a boundary.
**Done 2026-08-22.** `docs/security-zones_v0.1.md` §§68 defines the `zones:`
shape, the workload-addressable resolved view, and membership-change evidence.
Membership is attached to an authoritative `workload_identity` in the same
service entry and compiled to the governed workload resource as `workload_id`,
`security_zone`, `security_zone_admission`, and
`security_zone_revision`. Caller identity remains subject context. A control
that governs the caller must name that workload role explicitly.
The dormant hardcoded `trust_zone: platform` is not reused; it must be retired
before `security_zone` is emitted. Membership changes require a reviewed source
change, a new content/source revision, and a compiler diff against the preceding
snapshot. Temporary relaxation is always an exception, never a membership edit.
**Carrier file settled by net-kingdom 2026-08-19 (see T01).** The declaration
rides `tenancy.yaml` under a reserved top-level `zones:` key, not a new root
file. The key is already permitted and deliberately unconstrained in
@ -604,7 +623,7 @@ Two things to decide anyway, and both belong in this task:
```task
id: ZONE-WP-0001-T06
status: todo
status: progress
priority: medium
state_hub_task_id: "8a000c18-6ee7-4328-99c7-53c490435316"
```
@ -613,6 +632,12 @@ state_hub_task_id: "8a000c18-6ee7-4328-99c7-53c490435316"
`net-kingdom/canon/standards/`, drafted here, published there. Owner-driven
landing, as ops-warden's WP-0015 maturity model was.
**Drafted 2026-08-22.** The owner draft is
`docs/security-zones_v0.1.md`. It incorporates net-kingdom Decisions 5.6.1 and
5.6.2, the T03 control profile, the T04 exception lifecycle, and the T05
declaration/compiler contract. It remains `progress` until the committed draft
has been offered to net-kingdom for owner-driven publication.
```task
id: ZONE-WP-0001-T07
status: todo