172 lines
8.7 KiB
Markdown
172 lines
8.7 KiB
Markdown
|
|
# Security layer model — ops-warden's assent (WARDEN-IN-0001)
|
||
|
|
|
||
|
|
**Date:** 2026-08-28
|
||
|
|
**Intake:** `WARDEN-IN-0001`
|
||
|
|
**Requested by:** gate-house, ratified as `GH-DEC-2026-001`
|
||
|
|
**Standard:** `net-kingdom/canon/standards/security-layer-model_v0.1.md` (proposed)
|
||
|
|
**Outcome:** assent to all three items; one declared non-conformance and one
|
||
|
|
proposed amendment to the standard.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## What was asked
|
||
|
|
|
||
|
|
gate-house asked ops-warden to assent to three boundary items:
|
||
|
|
|
||
|
|
1. **ops-warden is Staff**, bound by §5 — Staff acts only through Engine APIs and
|
||
|
|
never holds a direct Tooling client.
|
||
|
|
2. **Doctrine versus runbook** — the security curriculum moves to gate-house; the
|
||
|
|
`NetKingdom Security Literacy` section in `INTENT.md` becomes lane-specific
|
||
|
|
runbooks that reference gate-house doctrine rather than restating it.
|
||
|
|
3. **The access lane / access rule demarcation** (§8) — ops-warden and ops-mason own
|
||
|
|
*lanes* (how a worker reaches a host); access-engine owns *rules* (whether they
|
||
|
|
may). This is the condition attached to renaming flex-auth to access-engine, so
|
||
|
|
ops-warden effectively holds a veto on that name.
|
||
|
|
|
||
|
|
Plus: add gate-house to the literacy and routing tables, and say so if moving the
|
||
|
|
curriculum out leaves ops-warden unable to instruct its own workers.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Item 1 — Staff, and the §5 problem it exposes
|
||
|
|
|
||
|
|
**Assent to the layer.** Staff is the right assignment and not a demotion.
|
||
|
|
ops-warden's artifacts are exactly what §3.4 describes: routing decisions,
|
||
|
|
workplans, runbooks, an audit trail. Its one production lane is non-deterministic
|
||
|
|
in the sense that matters — it is an operator front door, not a contract.
|
||
|
|
|
||
|
|
**But §5 is violated today, and by the one lane ops-warden permanently owns.**
|
||
|
|
The rule is deliberately greppable, so grepping is the honest response:
|
||
|
|
|
||
|
|
| Path | Tooling contact | Kind | Whose credential |
|
||
|
|
| --- | --- | --- | --- |
|
||
|
|
| `src/warden/vault.py` (`VaultCA.sign`) | `POST <bao>/v1/<mount>/sign/<role>` | **write** | broker-issued token held by ops-warden's process |
|
||
|
|
| `src/warden/desk.py` | `bao kv put` (paste-once provisioning) | **write** | founder's, at the desk |
|
||
|
|
| `src/warden/taint.py` | `bao kv metadata get` | read (metadata only, never data) | caller's |
|
||
|
|
| `src/warden/proxy.py` (`warden access --fetch/--exec/--wrap`) | catalog `fetch_command` | read | **the caller's own** |
|
||
|
|
|
||
|
|
Two of these are not really ops-warden's clients. `proxy.py` runs the owner's tool
|
||
|
|
under the caller's identity and supplies no authority of its own — that is
|
||
|
|
`ADR-0002`, conduit not broker, and it is arguably outside §5's target. `taint.py`
|
||
|
|
reads metadata only, and fits §5's read-only-observation allowance once declared.
|
||
|
|
|
||
|
|
**`VaultCA` does not have that defence.** It is a direct OpenBao client, in a Staff
|
||
|
|
repository, performing a write, presenting a token from its own environment. It is
|
||
|
|
production-verified and it is the SSH lane — the single thing ops-warden owns
|
||
|
|
permanently. Under §5 as written, adopting this standard puts ops-warden's core
|
||
|
|
lane in violation on the day it is adopted.
|
||
|
|
|
||
|
|
The escape hatch §5 offers does not fit: it covers *read-only observation for
|
||
|
|
diagnostics*, and signing is a write. The route §5 prescribes does fit —
|
||
|
|
|
||
|
|
> *A Staff repository needing a capability no engine exposes MUST raise that as an
|
||
|
|
> engine gap, not solve it locally.*
|
||
|
|
|
||
|
|
— and no engine exposes SSH certificate signing. `secrets-engine` owns credential
|
||
|
|
abstraction, custody and lifecycle, which is the layer this belongs in, but it
|
||
|
|
fronts no SSH-CA API today.
|
||
|
|
|
||
|
|
**So ops-warden assents and declares the non-conformance rather than negotiating an
|
||
|
|
exemption.** `VaultCA` is recorded in `INTENT.md` as a declared §5 exception with a
|
||
|
|
named intended owner (`secrets-engine`), a blocker (no SSH-CA engine surface), and a
|
||
|
|
review date. That is `ADR-0003` — cover gaps, never silently own them — applied to
|
||
|
|
ops-warden itself instead of to someone else's lane.
|
||
|
|
|
||
|
|
### Proposed amendment to the standard
|
||
|
|
|
||
|
|
§5 has exactly one shape for a Staff repository that legitimately touches Tooling:
|
||
|
|
read-only diagnostics. That shape is too narrow to describe the estate as it exists,
|
||
|
|
and a rule with no lane for a real, sanctioned case gets satisfied by relabelling
|
||
|
|
rather than by closing the gap.
|
||
|
|
|
||
|
|
Recommend §5 gain a second shape: a **declared engine gap** — a Staff repository MAY
|
||
|
|
hold a Tooling client for a capability no engine exposes, provided it is declared in
|
||
|
|
`INTENT.md` with an intended owner, the blocker, and a review date, and provided the
|
||
|
|
declaration is machine-readable so the conformance check in §10 can distinguish a
|
||
|
|
tracked gap from an undeclared violation.
|
||
|
|
|
||
|
|
ops-warden already runs this machinery for other repositories' lanes: 27 catalog
|
||
|
|
entries carry `delegation:` with `intended_owner` and `blocked_on`, and
|
||
|
|
`warden route gaps` lists them (WP-0030). It is offered, not imposed — the standard
|
||
|
|
is gate-house's.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Item 2 — Doctrine versus runbook
|
||
|
|
|
||
|
|
**Assent.** The `NetKingdom Security Literacy` section is what gate-house says it is:
|
||
|
|
evidence that the curriculum had no owner, so it accreted in whatever `INTENT.md`
|
||
|
|
was open. That is the same failure `risk-nexus` names for findings and the same one
|
||
|
|
`ADR-0001` prevents for catalog procedure. ops-warden has argued this rule twice
|
||
|
|
against other repositories; it applies here.
|
||
|
|
|
||
|
|
The boundary, drawn precisely:
|
||
|
|
|
||
|
|
| Moves to gate-house | Stays with ops-warden |
|
||
|
|
| --- | --- |
|
||
|
|
| Why the planes are separated; the authority model | Which subsystem owns which credential need |
|
||
|
|
| What "posture", "zone", "authority ceiling" mean | How to obtain a cert, a lease, a login — per lane |
|
||
|
|
| The security curriculum a worker is taught | The runbook a worker executes |
|
||
|
|
| Doctrine a lane must conform to | Evidence of conformance for ops-warden's lanes |
|
||
|
|
|
||
|
|
**gate-house's test question, answered: no, it does not leave ops-warden unable to
|
||
|
|
instruct its workers — and the reason is worth recording.** What actually instructs
|
||
|
|
an ops-warden worker is not the prose in `INTENT.md`. It is `warden plan "<need>"`,
|
||
|
|
`warden route find`, and `.claude/rules/credential-routing.md`, which is inlined into
|
||
|
|
every repository's agent instructions precisely because credential routing is
|
||
|
|
high-frequency and high-risk. That surface is executable, lane-specific, and
|
||
|
|
unambiguously runbook. It does not depend on the literacy table, and moving doctrine
|
||
|
|
out does not weaken it.
|
||
|
|
|
||
|
|
If anything the move improves it: the literacy table has been a second, prose copy of
|
||
|
|
what `registry/routing/catalog.yaml` states machine-readably, which is the
|
||
|
|
double-source failure `ADR-0001` exists to stop.
|
||
|
|
|
||
|
|
**One thing must not move with it.** `.claude/rules/credential-routing.md` stays
|
||
|
|
inline in this repository and in every other. It is not doctrine and not a
|
||
|
|
curriculum; it is the anti-pattern list an agent needs *before* it acts, and a
|
||
|
|
reference to a document in another repository would not be read in time.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Item 3 — Access lane versus access rule
|
||
|
|
|
||
|
|
**Assent, unconditionally, and the veto on `access-engine` is not exercised.**
|
||
|
|
|
||
|
|
ops-warden is already built this way. `ADR-0005` implements one lane narrowly and
|
||
|
|
routes everything else; `ADR-0002` makes it a conduit that never decides; `ADR-0009`
|
||
|
|
has ops-warden compile membership attributes and apply a zone's failure mode while
|
||
|
|
flex-auth owns the stance. ops-warden consumes decisions; it has never rendered one.
|
||
|
|
The demarcation costs nothing because it describes what is already true.
|
||
|
|
|
||
|
|
`access-engine` is also the better name. ops-warden's own routing table has had to
|
||
|
|
say "authorization" for the decision and "access" for the route for a year, and the
|
||
|
|
collision is visible in every playbook.
|
||
|
|
|
||
|
|
**One operational condition, on execution rather than on the ruling.** The rename is
|
||
|
|
598 references across 82 files in this repository alone — catalog `owner:` fields,
|
||
|
|
`registry/flex-auth/`, `src/warden/policy.py`, the production registry snapshot
|
||
|
|
builder, playbooks, and the `.claude/rules/` files that other repositories inline.
|
||
|
|
Ops-warden asks for a deprecation window in which both names resolve, rather than a
|
||
|
|
flag day; ops-warden will do its own migration inside that window. This is a request
|
||
|
|
about sequencing, not a reservation about the name.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Item 4 — gate-house is missing from every table
|
||
|
|
|
||
|
|
Correct, and fixed in this pass. gate-house is added to the literacy/routing table
|
||
|
|
in `INTENT.md` as the owner of doctrine, invariants, authority context, and
|
||
|
|
conformance review — with the routing rule stated explicitly: **doctrine and
|
||
|
|
authority-model questions go to gate-house; policy decisions continue to go to
|
||
|
|
access-engine.** Those are different questions and the distinction is the whole
|
||
|
|
point of §6.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Recorded as
|
||
|
|
|
||
|
|
- `ADR-0010` — ops-warden is Staff; lanes not rules; the declared §5 exception
|
||
|
|
- `INTENT.md` — layer declaration, reworked routing table, gate-house row
|
||
|
|
- `WARDEN-IN-0001` — closed, outcome `assented`
|