ops-warden/wiki/CredentialRouting.md
tegwick 537d551ef2 Route railiance01 admin kubeconfig through an attended lane
Assistant: grok
Assistant-Session: 01a1625d-4770-76a0-8dee-7f5c514a47eb
2026-10-22 08:53:33 +02:00

14 KiB

Credential Routing — NetKingdom Access Desk

Date: 2026-06-17

Use this page when a development worker (human, kaizen agent, CI job, or custodian tool) needs access or credentials and is unsure which subsystem owns the request.

ops-warden maintains this routing guide. It issues SSH certificates directly. For every other credential type, use the routed owner path. warden access may also assist: it renders the owner, auth method, path, and command shape and, for exec_capable catalog lanes, can proxy the owner's tool as the caller. That is a transparent conduit, not custody: do not paste secrets into Git, State Hub, agent chat, or workplans.

Practice follows SecurityCanon SEC-DSM 1.0.0 (security-canon/infospace/standards/devops-secrets-management/SecurityCanonDevOpsSecretsManagementStandard.md), which Gate House teaches. Prefer, in order: native identity, federated identity, an ephemeral credential, an automatically rotated secret, then a vaulted static secret (§5, decision procedure §37). SSH certificates are the ephemeral path this repo issues. A static secret stays in the owner's custody. This page routes to that owner. It does not collect the value.


Quick decision tree

What do you need?
|
+-- Log in as a human / get OIDC claims / MFA
|       -> key-cape (lightweight) or Keycloak (expanded)
|          net-kingdom/docs/platform-identity-security-architecture.md
|
+-- Permission to perform an action on a resource
|       -> flex-auth (policy decision)
|          flex-auth/INTENT.md
|
+-- API key, DB password, provider token, K8s secret, dynamic lease
|       -> OpenBao (after flex-auth approval where policy requires it)
|          railiance-platform/docs/openbao.md
|          NEVER ops-warden as owner or store
|
+-- S3 / object-storage temporary credentials
|       -> NK-WP-0007 vending path (flex-auth + OpenBao + storage STS)
|          net-kingdom/docs/object-storage-sts-credential-vending.md
|          NEVER ops-warden as owner or store
|
+-- SSH certificate for host / ops reachability (adm/agt/atm)
|       -> ops-warden (warden sign / cert_command)
|          wiki/OpsWardenConfig.md
|
+-- SSH tunnel / port forward (already have or will get a cert)
|       -> ops-bridge
|          ops-bridge tunnels.yaml + cert_command from ops-warden
|
+-- Host accepts your SSH principal / force-command on server
|       -> railiance-infra Ansible
|          /etc/ssh/auth_principals/, sshd hardening

Under two minutes: match your need to a branch above, open the linked doc, and treat non-SSH branches as owner-routed work. warden access can advise or proxy an exec_capable lane, but it does not make ops-warden the owner of the value.


Routing table

I need… Subsystem ops-warden role
Interactive login, OIDC token, MFA key-cape / Keycloak Assist: advise; proxy the login lane when the catalog entry is exec_capable
"May I do X on resource Y?" flex-auth (+ Topaz PDP) Route; policy gate for SSH/access proxies where configured
OpenRouter / LLM provider API key OpenBao → K8s Secret Assist: route; proxy only as caller when the catalog lane is exec_capable
Inter-Hub operator / runtime API key OpenBao or 0600 temp file Assist: route/custody notes; see wiki/InterHubBootstrapAccessLane.md
Database or service password OpenBao dynamic/KV Assist: route; proxy only as caller when the catalog lane is exec_capable
Short-lived SSH cert for operator ops-warden (adm-*) Issue via warden sign
Short-lived SSH cert for agent ops-warden (agt-*) Issue via warden sign / wrapper
Short-lived SSH cert for CI/cron ops-warden (atm-*) Issue via warden sign / warden issue
Tunnel to remote service ops-bridge Consumer of cert_command
Principal file on host railiance-infra Document only

Routing catalog index

These needs are also carried in the machine-readable pointer catalog (registry/routing/catalog.yaml, surfaced via warden route — WARDEN-WP-0011). The catalog is a pointer-and-assist layer: it names the owner, links the doc, and carries secret-free handoff templates for warden access. Only the SSH row is something ops-warden executes with its own authority. Non-SSH exec_capable rows run the owner's tool as the caller and preserve owner custody. Every execution position is classified permanent / native / interim (warden route gaps lists the interim set — WARDEN-WP-0030).

Catalog id What ops-warden answers What the worker does next
ssh-cert-host-access Issues the cert (warden sign) Use the cert / wire it into cert_command
ops-warden-warden-sign-token "railiance-platform broker owns the warden-sign lease — use credential exec" railiance-platform/scripts/credential.py exec --grant ops-warden/warden-sign (see playbook)
openbao-api-key "OpenBao owns this — here is the path/command shape" Call OpenBao directly, or use warden access --fetch/--exec as yourself when the lane is exec_capable
openbao-platform-admin-login "This is an attended OpenBao administration identity act, not workload secret retrieval" Use KeyCape-backed OIDC/MFA at auth/netkingdom, role platform-admin; never substitute a workload role or root token
kubernetes-railiance01-admin "Attended railiance01 admin kubeconfig; the agent default path is ops-mason-builder" Prefix kubectl with KUBECONFIG=/home/worsch/.kube/config-railiance01. Do not fetch the file.
openbao-shamir-recovery-ceremony "This is an attended trust-root ceremony, not secret provisioning" Obtain one explicit approval and follow the railiance-platform recovery checklist with the existing out-of-band custodians; never send shares through Warden
flex-auth-policy-check "flex-auth decides — here is the policy doc" Query flex-auth / embed the PEP
key-cape-oidc-login "key-cape / Keycloak owns identity" Authenticate via IAM Profile, or use the warden access login lane as yourself
ops-bridge-tunnel "ops-bridge owns transport — supply a cert_command" Open the tunnel with ops-bridge
railiance-infra-principals "railiance-infra deploys host principals" Run the infra Ansible
activity-core-issue-sink "activity-core + issue-core own emission — pair ISSUE_CORE_* env vars" See wiki/playbooks/activity-core-issue-sink.md
inter-hub-bootstrap-ssh "Inter-Hub bootstrap SSH envelope — attended vs unattended branches" See wiki/InterHubBootstrapAccessLane.md
issue-core-ingestion-api-key "railiance-platform OpenBao KV + ESO deliver ISSUE_CORE_API_KEY — here is the path" ESO consumes in-cluster; warden access issue-core-ingestion-api-key --fetch ISSUE_CORE_API_KEY as yourself
openrouter-llm-connect "railiance-platform OpenBao KV + ESO deliver OPENROUTER_API_KEY to activity-core" ESO consumes in-cluster; warden access openrouter-llm-connect --fetch OPENROUTER_API_KEY as yourself (risk: high)
reuse-surface-hub-write-token "railiance-platform OpenBao KV + ESO deliver REUSE_SURFACE_TOKEN to reuse-surface" ESO consumes in-cluster; warden access reuse-surface-hub-write-token --fetch as yourself
railiance-backup-offsite-lane "railiance-platform OpenBao KV for Nextcloud WebDAV + age recovery" warden access railiance-backup-offsite-lane --out FILE (risk: high; agents: no raw stream)
forgejo-admin-api-token "railiance-platform OpenBao KV for Forgejo admin PAT" warden access forgejo-admin-api-token --out FILE (risk: high)
binky-company-email-imap "tenant IMAP on tenants/binky/company-email/imap (IONOS)" warden access binky-company-email-imap --out FILE (risk: high)
binky-qonto-api "tenant Qonto API on tenants/binky/qonto-api (API_KEY+API_USER)" warden access binky-qonto-api --out FILE (risk: high)
net-kingdom-lldap-bind-credential "railiance-platform custody for the LLDAP bind credential used by identity-provisioner and the privacyIDEA resolver" Follow the owner-approved NetKingdom reconciliation runbook; lane is currently unresolved and never fetches a value
net-kingdom-privacyidea-admin-token "railiance-platform custody for the privacyIDEA administrative token used by attended resolver reconciliation" Follow the owner-approved NetKingdom reconciliation runbook; lane is currently unresolved and never fetches a value
keycape-client-secret-generate "railiance-platform's broker generates a KeyCape client secret inside custody for an accepted SecurityCase. The value is never returned" bao login to role credential-broker-keycape-client-secret-generate, then credential.py generate --case-file ... --case-ref ... (see playbook). Agents are refused
audit-core-senders "ops-mason built the audit-core sender registry in OpenBao. audit-core reads it through ESO only" Nobody reads the registry. A sender gets its own exact-path projection (see playbook table)

Promotion criteria: wiki/playbooks/catalog-lane-promotion.md.
High-risk / agent boundary: wiki/playbooks/agent-read-boundary.md.
EXPOSED taint: wiki/playbooks/exposed-taint.md · warden taint <id>.
Tenant secrets: mount tenants/ — path tenants/<tenant>/<workload>/<bundle> (see wiki/playbooks/tenant-secret-onboarding.md, WARDEN-WP-0028). Not under platform/workloads/.

Draft (hidden from default lookup until owner path ships — warden route list --all):

Catalog id Routing focus Playbook
object-storage-sts NK-WP-0007 STS vending path wiki/playbooks/object-storage-sts.md
database-dynamic-credentials OpenBao database secrets engine wiki/playbooks/database-dynamic-credentials.md
fluid-telegram-operator ops-mason attended OIDC lane for the Hall of Helix campaign (pending owner-run checks) wiki/playbooks/fluid-telegram-operator.md

ops-warden answers where + who + how. The worker still acts on the owning system. When warden access proxies a non-SSH lane, it does so as the caller and stores no value; the owner remains OpenBao, key-cape, flex-auth, or the routed subsystem.


Policy gate for proxied credential reads

warden access <need> with --exec, --fetch, --to-file, --wrap or --fingerprint runs a flex-auth read check before any fetch. That check goes to the fetch evaluator flex-auth-ops-warden-fetch (policy.fetch_flex_auth_url, workstation http://127.0.0.1:19091 through ops-bridge tunnel flex-auth-ops-warden-fetch-railiance01). It does not go to the SSH signing pin flex-auth-ops-warden (policy.flex_auth_url, 127.0.0.1:19090), which admits only the ops-warden system. If the fetch evaluator is unset or unreachable, the fetch is refused (exit 4). It is never sent to the signing pin and never allowed by default. The gate line of warden access <need> names the evaluator in use. Config: wiki/OpsWardenConfig.md → "Two evaluators" (CUST-WP-0075).

Examples — do NOT ask ops-warden to own or vend

Request Correct path
"VAULT_TOKEN for ops-warden production sign / policy-gate smoke" railiance-platform credential broker — warden route show ops-warden-warden-sign-token
"Populate OPENROUTER_API_KEY for llm-connect" Operator → OpenBao custody; delivery via warden route show openrouter-llm-connect
"Store Inter-Hub admin key for bootstrap" Operator → OpenBao or IHUB_OPERATOR_KEY_FILE (CUST-WP-0049)
"Give me Vault root token" Break-glass ceremony → railiance-platform/docs/openbao.md
"S3 credentials for artifact upload" NK-WP-0007 / artifact-store consumer path
"JWT for my app" key-cape / Keycloak IAM Profile

No duplicate ownership. Commands that would make warden a store, IdP, or transport owner — warden secret, warden bao, warden login as an identity service, or warden tunnel — do not exist. A future warden policy lookup, if added by WARDEN-WP-0015, is metadata/conformance only; flex-auth remains the PDP. The canonical anti-pattern table lives in wiki/AccessRouting.md#anti-patterns-not-coming-to-ops-warden; it is not restated here.


Examples — ops-warden IS correct

Request Command / pattern
ops-bridge tunnel needs a cert cert_command: warden sign <actor> --pubkey <path>
Agent reaching bootstrap host agt-codex-interhub-bootstrap — wiki/InterHubBootstrapAccessLane.md
Check cert expiry before shift warden status <actor>
New tunnel actor warden inventory add — wiki/ActorInventoryPatterns.md
Lab without OpenBao backend: local — wiki/OpsWardenConfig.md

Typical flows

Human operator → remote host

  1. Identity: key-cape login if web/API access needed (optional for pure SSH).
  2. SSH cert: warden sign adm-<you> --pubkey ~/.ssh/id_ed25519.pub.
  3. Tunnel (if needed): ops-bridge with cert_command pointing at warden.
  4. Host: principal deployed by railiance-infra.

Kaizen / Codex agent → attended task

  1. Register actor: agt-codex-<task> per wiki/ActorInventoryPatterns.md.
  2. SSH cert: WARDEN_ACTOR=... ops-ssh-wrapper ssh ... or warden sign.
  3. Secrets for task (API keys): OpenBao path — not warden.
  4. Tunnel: ops-bridge if required.

CI automation → scheduled job

  1. Actor: atm-<job> with narrow principal and low TTL (≤ 8 h).
  2. warden issue atm-<job> or sign with pre-provisioned key.
  3. No long-lived keys in CI env vars.

When guidance drifts

NetKingdom security architecture is canonical in net-kingdom. When it changes (OpenBao, IAM Profile, new bootstrap lanes), ops-warden updates:

  • This file
  • wiki/NetKingdomSecurityMap.md
  • SCOPE.md / INTENT.md as needed

Report drift via custodian workplan or State Hub message to ops-warden.


See also

  • INTENT.md — steward mission
  • wiki/AccessRouting.md — what ops-warden issues vs routes (role and boundary)
  • wiki/NetKingdomSecurityMap.md — component literacy
  • wiki/WorkloadSecurityPosture.md — dev/test/prod posture, M0-M3 maturity, and blocker triage
  • wiki/ActorInventoryPatterns.md — actor naming
  • wiki/OpenBaoSshEngineChecklist.md — production SSH signing verify
  • net-kingdom/docs/platform-identity-security-architecture.md — platform canon