# NetKingdom Security Map (ops-warden view) Date: 2026-06-17 Condensed literacy guide for ops-warden stewards and development workers. Canonical source remains `net-kingdom/docs/platform-identity-security-architecture.md`. ops-warden **implements** the operational SSH lane and **documents** how the other lanes connect. --- ## Planes ```text Bootstrap plane railiance-infra, railiance-cluster, net-kingdom bootstrap Platform control key-cape, flex-auth, OpenBao, Topaz, railiance-platform Tenant plane railiance-apps, coulomb workloads, future tenants Operational access ops-warden (SSH certs), ops-bridge (tunnels) ``` --- ## Component map | Component | Answers | Credential types | ops-warden | | --- | --- | --- | --- | | **key-cape** | Who are you? (lightweight IAM) | OIDC tokens, MFA | Route — do not issue | | **Keycloak** | Who are you? (expanded IAM) | OIDC/SAML federation | Route — do not issue | | **privacyIDEA** | MFA / step-up | OTP, hardware tokens | Route — do not issue | | **flex-auth** | May you do this action? | Policy decisions, audit envelopes | Future SSH pre-sign; route today | | **Topaz** | PDP runtime for flex-auth | Authorization evaluations | Route — do not issue | | **OpenBao** | Runtime secret authority | API keys, DB creds, leases, K8s auth | SSH engine **signing backend** only | | **ops-warden** | SSH ops access | Short-lived SSH certificates | **Own and issue** | | **ops-bridge** | Tunnel transport | Uses certs via cert_command | Consumer | | **railiance-infra** | Host enforcement | auth_principals, sshd | Route — deploy hosts | | **railiance-platform** | Platform deploy | OpenBao, Postgres, ingress | Route — do not deploy from warden | --- ## Credential lanes (summary) | Lane | Owner | Lifetime | Worker entrypoint | | --- | --- | --- | --- | | Identity | key-cape / Keycloak | Session / token TTL | Login / OIDC | | Authorization | flex-auth | Per request | Policy API / embedded PEP | | Runtime secrets | OpenBao | Lease-bound | `bao` CLI, K8s ESO, app integration | | SSH operational | ops-warden | adm 48h / agt 24h / atm 8h | `warden sign` | | Tunnel | ops-bridge | Session | `bridge` + cert_command | Full routing: `wiki/CredentialRouting.md`. --- ## Trust flow (simplified) ```text Worker request -> Identity? key-cape / Keycloak -> Authorized? flex-auth -> Secret material? OpenBao -> SSH cert? ops-warden -> Tunnel? ops-bridge (cert from warden) -> Host accepts? railiance-infra principals ``` OpenBao does **not** replace identity or authorization. flex-auth decides; OpenBao stores/issues; ops-warden signs SSH certs when host reachability is the need. --- ## Service-to-service caller authentication (in-cluster) **Status:** recommended pattern, 2026-08-17. Raised by flex-auth (FLEX-WP-0015 T02): `POST /v1/check` and `/v1/batch_check` authenticate no caller, so any workload with network reach can assert any subject and receive an authoritative allow. **There is no prior estate pattern for this.** What exists covers adjacent needs and none of them covers in-cluster service→service HTTP: | Existing mechanism | What it authenticates | Why it does not apply | | --- | --- | --- | | ops-warden SSH certificates | `adm`/`agt`/`atm` actors to hosts | Host reachability, not an HTTP call between pods | | KeyCape `client_credentials` | Workload OIDC clients (`rapp-qonto-keycape-client`) | Needs a client secret per caller — a custodied lane per consumer | | OpenBao AppRole | Host-standing non-interactive workers | `role_id`+`secret_id` on disk; the WP-0030 register already flags AppRole as having **no owner front door** for minting or rotating | ### Recommendation: Kubernetes ServiceAccount TokenReview Use the caller's **projected** ServiceAccount token with an explicit `audience` (e.g. `flex-auth`); the callee verifies it via `TokenReview`. Why this and not the alternatives: - **It introduces no new secret material.** A shared-secret header (flex-auth's option (c)) would immediately become a `risk: high` credential lane with a rotation owner, per calling system, on the authorization path — precisely the interim-proxy debt the WP-0030 delegation register exists to stop growing. ops-warden would end up fronting it. - **It matches the estate's short-lived-credential doctrine.** A projected, audience-scoped SA token has the same shape as `warden sign` output: bounded TTL, issued by an authority, verified on use, never stored. - **mTLS (option (b)) is the stronger end state but has no owner.** It requires an X.509 workload CA, and no component owns one today — ops-warden issues SSH certificates, not workload X.509. Adopting mTLS means first answering *who owns the workload CA*, which is a permanent-ownership question, not a rollout task. Record it as future direction; do not block on it. Implementation notes that matter: - Use a **projected token volume with an explicit `audience`**, not the legacy automount token. Keep `automountServiceAccountToken: false` and add the projected volume per Deployment. An audience-scoped token stolen from a pod cannot be replayed against the kube-apiserver or another service. ### Authenticate *and* bind — but keep policy in the policy engine Bind the `system` asserted in the request to the authenticated ServiceAccount and reject a mismatch. That is identity binding, not authorization: it is cheap and it costs nothing extra when a new consumer arrives, since a caller must have a mapping regardless. Do **not** put a caller allowlist for resource types ("only ops-warden may ask about `ssh-certificate`") in the authentication middleware. flex-auth is the estate's policy engine; encoding that rule in its own admission layer puts authorization in two places, where only one of them is reviewable and versioned. Express it in the policy package. ### Rollout Warn-only first, then fail-closed. ops-warden adopts the calling side on its own schedule rather than in lockstep. The binding condition is sequencing, not a date: ```text flex-auth warn-only -> ops-warden pre-sign gate presents its SA token -> logs clean of unauthenticated callers -> flex-auth fail-closed -> zone-specific enforce stance (flex-auth policy package) ``` An enforce stance must not be assigned while `/v1/check` still answers unauthenticated callers. ops-warden has no global enable switch or gate bypass; it applies the compiled zone stance and its local per-zone failure mode. **Division of the call:** the mechanism above is an architecture recommendation and ops-warden's to make. Accepting the pod-spec change and the rollout timing are the operator's. This is a *pattern*, not a credential lane, so it gets no `registry/routing/catalog.yaml` entry — the catalog indexes credential needs and their owners. --- ## NetKingdom documents to watch | Document | Why ops-warden cares | | --- | --- | | `platform-identity-security-architecture.md` | Planes, secret path, SSH path | | `responsibility-map.md` | Operational SSH dependency section | | `platform-identity-security-architecture.md` | Operational SSH Path section | | `platform-root-custody.md` | OpenBao ceremony — not warden's job | | `object-storage-sts-credential-vending.md` | S3 creds — never warden | | `canon/standards/iam-profile_v0.2.md` | Claims for future policy-gated sign | When these change, update ops-warden wiki and `wiki/CredentialRouting.md`. --- ## Recursive platform rule Tenant admins (including `tenant:coulomb`) must not gain platform-root authority. ops-warden SSH actors should use **narrow principals** for agent and automation work — not platform-admin equivalents on hosts. --- ## See also - `INTENT.md` - `wiki/AccessRouting.md` — issue-vs-route role and boundary - `wiki/CredentialRouting.md` - `wiki/PolicyGatedSigning.md` (future flex-auth hook) - `net-kingdom/docs/platform-identity-security-architecture.md`