From b7095bbabd2d2e673facdd506f81e534840ff8e3 Mon Sep 17 00:00:00 2001 From: tegwick Date: Sat, 22 Aug 2026 14:03:46 +0200 Subject: [PATCH] Complete security zone model and canon draft Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a0291a-1e87-7151-9934-fcbfe3f65eb1 --- INTENT.md | 8 +- SCOPE.md | 18 +- WORK-RECORDS.md | 6 +- docs/security-zones_v0.1.md | 290 ++++++++++++++++++ workplans/ZONE-WP-0001-security-zone-model.md | 49 ++- 5 files changed, 346 insertions(+), 25 deletions(-) create mode 100644 docs/security-zones_v0.1.md diff --git a/INTENT.md b/INTENT.md index 83b29a1..7d76775 100644 --- a/INTENT.md +++ b/INTENT.md @@ -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. diff --git a/SCOPE.md b/SCOPE.md index d549ef5..28033f6 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -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. T01–T05 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. --- diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index f09ce9b..803010e 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -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 | diff --git a/docs/security-zones_v0.1.md b/docs/security-zones_v0.1.md new file mode 100644 index 0000000..26eedcf --- /dev/null +++ b/docs/security-zones_v0.1.md @@ -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: +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: +``` + +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. diff --git a/workplans/ZONE-WP-0001-security-zone-model.md b/workplans/ZONE-WP-0001-security-zone-model.md index d974da4..ff655dd 100644 --- a/workplans/ZONE-WP-0001-security-zone-model.md +++ b/workplans/ZONE-WP-0001-security-zone-model.md @@ -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` §§4–5. `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` §§6–8 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