# Access Routing — what ops-warden answers Date: 2026-06-18 ops-warden **issues short-lived SSH certificates**, **routes every other credential need to the subsystem that owns it**, and **assists** with obtaining it through the `warden access` front door. This page states that role plainly so it cannot be misread as a desk that wraps the platform. - **What ops-warden executes:** the SSH certificate lane only (`warden sign`, `cert_command`, `ops-ssh-wrapper`). - **What ops-warden answers:** *where* a credential need belongs and *who owns it* — pointing at the owner's docs, never restating their procedure. - **What ops-warden assists with:** `warden access` renders the exact auth/path/command for any need and, for `exec_capable` lanes, **proxies the fetch as the caller** — a transparent, policy-gated, audited conduit that holds, caches, and logs nothing. - **What ops-warden never does:** *own* a secret store, *establish* identity, *decide* policy, open tunnels, or deploy hosts. The assist conduit uses **your** identity and owns none of these. See `OperatorAccessAssist.md`. For the worker-facing decision tree see `CredentialRouting.md`; for component literacy see `NetKingdomSecurityMap.md`. This page is the steward's statement of **role and boundary**. --- ## Issue vs route | Need | Subsystem | ops-warden role | Who acts | | --- | --- | --- | --- | | SSH cert for host/ops access (`adm`/`agt`/`atm`) | **ops-warden** | **Issue** (`warden sign`) | ops-warden signs; worker uses cert | | API key / DB cred / dynamic lease | OpenBao | Route — point at path | Worker calls OpenBao | | "May I perform action X?" | flex-auth (+ Topaz PDP) | Route — point at policy | Worker/PEP calls flex-auth | | Login / OIDC token / MFA | key-cape / Keycloak | Route — point at IAM Profile | Worker authenticates | | Object-storage STS / S3 creds | net-kingdom + flex-auth + OpenBao | Route — point at vending path | Worker follows NK-WP-0007 | | SSH tunnel / port forward | ops-bridge | Route — supply `cert_command` | ops-bridge opens tunnel | | Host principal / force-command | railiance-infra | Route — point at Ansible | infra deploys host | | OpenBao cluster init / unseal | railiance-platform | Route — point at ceremony | platform operates | Only the first row is something ops-warden **executes**. Every other row is a **pointer**: ops-warden names the owner and the doc, and the worker acts on the owning system directly. **Assist layer (`warden access`).** For routed rows, ops-warden goes beyond the pointer: it renders the exact auth method, path template, and command, and — where the catalog marks a lane `exec_capable` (today: OpenBao secret reads, key-cape login) — **proxies the call as the caller**. This does not change ownership: the secret stays in OpenBao, the decision stays in flex-auth, the identity stays in key-cape. ops-warden is a transparent conduit using the caller's identity, never a custodian of the value. The boundary that keeps this sound is in `OperatorAccessAssist.md#the-conduit-vs-broker-boundary`. --- ## Anti-patterns (not coming to ops-warden) ops-warden does not **own** custody, identity, authorization, or transport — those belong to other subsystems. The assist layer (`warden access`) may *proxy* a call as the caller, but it never becomes the owner. Don't reach for a command that implies ownership: | Tempting command | Why it's wrong | Right path | | --- | --- | --- | | `warden secret` / `warden bao` (as a store/vend) | ops-warden owns no secret store and vends nothing | OpenBao; to obtain *as yourself*, `warden access --fetch` | | `warden login` (as an identity owner) | ops-warden does not establish identity | key-cape / Keycloak; to run the login *as yourself*, `warden access --fetch` (login lane) | | `warden policy` (as a decision) | ops-warden does not decide authorization | flex-auth makes the call; ops-warden only gates its own proxy on it | | `warden tunnel` | ops-warden does not manage transport | ops-bridge | The distinction: a **standing broker** (warden's own secret-read token, a cache of values) is forbidden; a **transparent conduit** (`warden access --fetch`, caller's identity, nothing retained) is sanctioned. ops-warden authors step-by-step procedure for exactly one lane — SSH issuance — because it owns it. For everything else it carries a **pointer** (and, for `exec_capable` lanes, a conduit), not a fork of the owner's runbook. See the no-double-source rule in `workplans/WARDEN-WP-0010-access-routing-charter.md` and the conduit-vs-broker boundary in `OperatorAccessAssist.md`. --- ## Routing lookup CLI (`warden route`) Agents and operators query the pointer catalog directly instead of re-deriving routing from wiki prose. The command group is **read-only** — it never calls OpenBao, flex-auth, key-cape, or any other subsystem, and never returns secret material. ```bash warden route list [--json] [--all] [--tag ] # active-only unless --all warden route list --stale [--stale-days 90] [--all] [--json] # past review cadence warden route show [--json] # owner + pointers; SSH adds steps warden route find "" [--json] [--all] # rank by keyword overlap ``` Agent-oriented examples: ```bash # "I need an API key" — find the owner, get a pointer, act there yourself warden route find "openrouter api key" --json warden route show openbao-api-key --json # → {"warden_executes": false, "next_action": "next action on `railiance-platform` — see `wiki/CredentialRouting.md#routing-table`"} # The one lane ops-warden executes: SSH. `show` appends the authored steps + cert pattern. warden route show ssh-cert-host-access --json # → {"warden_executes": true, "cert_command": "warden sign --pubkey ", "steps": [...]} ``` `show` on a routed (non-SSH) need always ends with **"next action on `` — see ``"** and never implies ops-warden performed anything. Draft scenarios (owner path not yet shipped) are hidden unless `--all`. --- ## Audience notes - **Human operators** read this page and `CredentialRouting.md` to choose the right subsystem, then follow that subsystem's own docs. - **Agents / CI** read the machine-readable routing catalog (`registry/routing/catalog.yaml`) via `warden route` (above) so routing does not have to be re-derived from wiki prose each session. - **Same truth, two shapes:** humans read the wiki; agents read the catalog. The catalog references wiki sections by anchor so the two cannot drift apart — a test (`tests/test_routing.py`) fails CI if any `wiki_ref` anchor stops resolving. --- ## How this stays aligned NetKingdom security architecture is canonical in `net-kingdom`. ops-warden tracks it: when canon changes, the wiki section is updated and the catalog pointer (`wiki_ref` + `canon_ref`) follows. ops-warden never overrides canon and never silently forks it. Report drift via a custodian workplan or a State Hub message to `ops-warden`. --- ## Drift review cadence Every catalog entry carries a `reviewed:` date (`YYYY-MM-DD`) — the last time an ops-warden steward confirmed the pointer still matches net-kingdom canon and the owner repo's shipped path. | Cadence | Action | | --- | --- | | **Quarterly** (default 90 days) | Run `warden route list --stale` — reconcile every listed entry against canon | | **On canon change** | When net-kingdom security docs change, review affected `canon_ref` entries immediately | | **On owner ship** | When an owning repo merges a new OpenBao path or playbook, promote `draft` → `active` and bump `reviewed` | | **On agent confusion** | If `warden route find` misses a common query, add `need_keywords` or a playbook — do not restate owner procedure in the catalog | ### Stale check (operators and agents) ```bash # Entries not reviewed in the last 90 days (default threshold) warden route list --stale # Include draft scenarios in the stale report warden route list --stale --all # Custom threshold (e.g. monthly review) warden route list --stale --stale-days 30 --json ``` For each stale entry: 1. Open `canon_ref` in net-kingdom — confirm ownership and vocabulary unchanged. 2. Open `wiki_ref` in this repo — update the playbook section if canon moved. 3. Confirm the owner path still exists (anti-stale rule: unshipped paths stay `draft`). 4. Bump `reviewed:` in `registry/routing/catalog.yaml` to today's date. 5. Run `uv run pytest tests/test_routing.py` — anchor resolution must still pass. CI enforces structural drift (every `wiki_ref` anchor resolves; no-double-source rule). The quarterly cadence catches **semantic** drift CI cannot detect — canon moved but anchors still resolve. --- ## See also - `CredentialRouting.md` — worker decision tree and routing table - `NetKingdomSecurityMap.md` — component literacy - `INTENT.md` — steward mission ("issue SSH, route the rest") - `workplans/WARDEN-WP-0010-access-routing-charter.md` — charter + no-double-source rule - `net-kingdom/docs/platform-identity-security-architecture.md` — platform canon