id: CCR-2026-0013
kind: credential-change-request
schema_version: 1
request_type: workload-kv-read
title: Core Hub runtime API token lane
status: verified
created: '2026-08-20'
updated: '2026-08-20'
requester:
  agent: codex
  reason: CORE-WP-0011 and RAPP-CORE-HUB-WP-0001 relocate Core Hub production to railiance01.
    The validated package requires CORE_HUB_API_TOKEN, but the value must move through
    platform custody rather than a copied Kubernetes Secret or Git. This request covers
    only the standing application token; PostgreSQL credentials remain dynamic database-engine
    leases.
review:
  required: true
  required_approvers:
  - platform-operator
  - core-hub-owner
  comments:
  - at: '2026-08-20T22:02:19+00:00'
    reviewer: platform operator / Core Hub owner (chat approval)
    decision: approved
    comment: 'State Hub decision 4f70311b-a4c4-4959-b1a1-cdd1be97d523: approved for
      the governed private Core Hub relocation; static API-token custody remains separate
      from dynamic PostgreSQL leases.'
  - at: '2026-08-20T22:03:00+00:00'
    reviewer: codex
    decision: binding_confirmed
    comment: Railiance01 has ServiceAccount external-secrets/external-secrets and
      the External Secrets deployment uses that exact identity. The proposed Kubernetes-auth
      bound claims match the live subject; store use remains independently limited
      to namespace core-hub.
target:
  domain: infotech
  tenant: core-hub
  workload: core-hub
  rapp: rapp-core-hub
  environment: production
  purpose: Project the existing Core Hub protected-API token into the private railiance01
    runtime through a namespace-limited ExternalSecret while preserving the token
    across the relocation window.
openbao:
  mount: platform
  kv_path: platform/workloads/core-hub/runtime
  fields:
  - CORE_HUB_API_TOKEN
  policy_name: workload-kv-read-core-hub-runtime
  policy_file: openbao/policies/workload-kv-read-core-hub-runtime.hcl
  auth:
    method: kubernetes
    mount: kubernetes
    role: external-secrets-core-hub-runtime
    bound_claims:
      service_account_names:
      - external-secrets
      service_account_namespaces:
      - external-secrets
    bound_claims_confirmed: true
    policies:
    - workload-kv-read-core-hub-runtime
    ttl: 15m
access_frontdoor:
  type: ops-warden
  catalog_id: core-hub-runtime-api-token
  selector: Core Hub runtime protected API token
  command: warden access core-hub-runtime-api-token --fetch CORE_HUB_API_TOKEN
  resolvable: false
  readiness: pending-review
delivery:
  surface: external-secrets
  target: ClusterSecretStore openbao-core-hub-runtime, limited to namespace core-hub,
    to ExternalSecret core-hub/core-hub-api-token and Secret core-hub-api-token. The
    rapp package consumes this Secret separately from runtime and migration PostgreSQL
    lease Secrets.
risk:
  classification: high
  notes:
  - The token authorizes protected Core Hub API operations and must not be printed,
    placed on argv, committed, or recorded in State Hub.
  - This CCR does not authorize a standing database password or a database URL in
    KV. Those come from the OpenBao database engine.
  - Preserve the current token during the relocation so existing protected API consumers
    do not fail at the same time as the infrastructure move.
  - Later rotation is coordinated with every protected API consumer because Core Hub
    currently accepts one token.
verification:
  positive:
  - An approved core-hub ExternalSecret syncs CORE_HUB_API_TOKEN into Secret core-hub-api-token
    without printing the value.
  - Protected API smoke succeeds against the private shadow endpoint using an injected
    token after the source database has been reconciled.
  negative:
  - A namespace outside core-hub cannot use openbao-core-hub-runtime.
  - A token without workload-kv-read-core-hub-runtime cannot read the KV data path.
  - The Core Hub workload identity cannot write or list sibling workload paths.
  activation_conditions:
  - Platform operator and Core Hub owner approve this CCR.
  - The source token is transferred through attended operator custody without entering
    logs, chat, Git, or State Hub.
  - The Kubernetes auth role and policy are applied to railiance01-local OpenBao and
    the bound service-account claims are verified.
  - The package consumes the API-token Secret separately from dynamic database lease
    Secrets.
  - Positive and negative evidence is recorded with non-secret timestamps or OpenBao
    audit references.
  evidence:
  - at: '2026-08-20T22:07:02+00:00'
    actor: platform operator / Core Hub owner (chat approval)
    kind: metadata_apply
    result: passed
    details:
    - OpenBao policy and auth-role metadata apply completed without secret values
  - at: '2026-08-20T22:11:45+00:00'
    actor: codex
    kind: secret_provisioned
    result: passed
    details:
    - Source API token transferred directly from CoulombCore Kubernetes custody to
      OpenBao KV version 1; value not printed or staged
  - at: '2026-08-20T22:11:45+00:00'
    actor: codex
    kind: positive_verification
    result: passed
    details:
    - Railiance01 stores Valid; API/runtime/migration ExternalSecrets SecretSynced
      at 2026-08-20T22:07:42Z with expected key names only
  - at: '2026-08-20T22:11:45+00:00'
    actor: codex
    kind: negative_verification
    result: passed
    details:
    - Both stores rejected core-hub-denial-probe with SecretSyncedError and created
      no target Secret; Kubernetes-auth token had read on exact data/metadata paths
      and deny on sibling/parent paths
  - at: '2026-08-20T22:11:46+00:00'
    actor: codex
    kind: database_role_separation
    result: passed
    details:
    - Runtime lease connected but CREATE was denied and pg_has_role(core_hub_migrate)=false;
      migration lease created and dropped bounded probe table; probe pods deleted
  - at: '2026-08-20T22:45:58+00:00'
    actor: codex
    kind: private_shadow_verification
    result: passed
    details:
    - 'Private railiance01 shadow: OpenBao KV and database stores Valid; least-privilege
      denial and role-separation probes passed; chart 0.3.1 rotated the runtime lease
      in place with Secret resourceVersion change, child PID change, stable pod UID,
      container restartCount 0->0, readiness true, and 5m refresh restored; post-rotation
      authenticated smoke 20260820224419-43dc05 passed all 10 checks; public Ingress
      remained absent.'
lifecycle:
  deactivate: Disable the front door and Kubernetes auth role, remove the ExternalSecret,
    and delete the materialized Secret only after Core Hub is retired or a reviewed
    fallback is active.
  rotate: Coordinate a new random token with all protected API consumers, update the
    OpenBao field through attended custody, wait for ESO sync, roll Core Hub and consumers,
    verify protected calls, then invalidate the old token.
  compromised: Disable protected writes, replace the token in OpenBao and every consumer,
    roll the workload, review Core Hub protected-operation logs, and open an incident
    follow-up.
state_hub:
  workplan_id: RPF-WP-0021
  task_id: RPF-WP-0021-T04
  decision_id: 4f70311b-a4c4-4959-b1a1-cdd1be97d523
  decision_api_url: http://127.0.0.1:8000/decisions/4f70311b-a4c4-4959-b1a1-cdd1be97d523
  decision_dashboard_url: http://127.0.0.1:3000/decisions
  decision_resolved_at: '2026-08-20T22:02:19Z'
