diff --git a/registry/routing/catalog.yaml b/registry/routing/catalog.yaml index 0e2cec8..d3ca951 100644 --- a/registry/routing/catalog.yaml +++ b/registry/routing/catalog.yaml @@ -583,7 +583,7 @@ entries: workload_ref: applicability: applicable unknown_reason: "The state-hub deployment has no authoritative workload identity declaration yet; the AppRole is the identity until it does." - need_keywords: [state-hub, statehub, forge, forgejo, derivation, derive, projection, private, repository, clone, FORGE_READ_TOKEN, ADR-012, work-records, unreadable] + need_keywords: [state-hub, statehub, forge, forgejo, derivation, derive, projection, private, repository, clone, FORGE_READ_TOKEN, ADR-012, work-records, unreadable, kubernetes-auth] owner_repo: ops-mason subsystem: OpenBao + Forgejo warden_executes: false @@ -594,13 +594,13 @@ entries: delegation: mode: native intended_owner: ops-mason - blocked_on: "Entry proposed ahead of the build (MASON-WP-0003-T03). Promote to active once MASON-WP-0003-T02 has created the policy, AppRole, and KV path and the negative capability check passes." + blocked_on: "Policy and Kubernetes auth role built and capability-verified 2026-08-27 (MASON-WP-0003-T02). Still draft: the KV path holds no token until paste_once_provision delivers one, and ServiceAccount state-hub/state-hub does not exist yet (STATE-WP-0084-T02). Promote to active once both land." reviewed: "2026-08-26" verified: unverified # ops-warden routes this and executes nothing: it issues SSH certificates # only and owns no secret store. ops-mason builds the structure; the forge # owner mints the value; paste_once_provision delivers it. - auth_method: "AppRole login (state-hub-forge-derivation) from the in-cluster state-hub workload" + auth_method: "Kubernetes auth (role state-hub-forge-derivation, ServiceAccount state-hub/state-hub) from the in-cluster state-hub workload" path_template: "platform/workloads/state-hub/forge-derivation (field FORGE_READ_TOKEN)" rotation: method: rotate diff --git a/wiki/playbooks/state-hub-forge-derivation-read.md b/wiki/playbooks/state-hub-forge-derivation-read.md index 0c316d3..3969485 100644 --- a/wiki/playbooks/state-hub-forge-derivation-read.md +++ b/wiki/playbooks/state-hub-forge-derivation-read.md @@ -1,7 +1,7 @@ # State Hub Forge Derivation Read Token -Date: 2026-08-26 (proposed) -Catalog: `state-hub-forge-derivation-read` (status `draft` until built) +Date: 2026-08-26 (policy and auth role built and verified 2026-08-27) +Catalog: `state-hub-forge-derivation-read` (status `draft` until the token and ServiceAccount land) Owner: `ops-mason` (built under `ops-mason/plans/state-hub-forge-derivation-read.md`, approved 2026-08-26) Read-only Forgejo token so the State Hub can clone **private** repositories and @@ -27,7 +27,7 @@ delivered through `paste_once_provision`. | Path | `platform/workloads/state-hub/forge-derivation` | | Secret field | `FORGE_READ_TOKEN` | | Policy | `workload-kv-read-state-hub-forge-derivation` (read on that path alone) | -| AppRole | `state-hub-forge-derivation` (`token_ttl=15m`, `token_max_ttl=30m`) | +| Auth | Kubernetes auth role `state-hub-forge-derivation`, bound to ServiceAccount `state-hub/state-hub` (`token_ttl=15m`, `token_max_ttl=30m`) | **Forgejo token scope:** repository **read**, organisation-wide. No push, no administration, no other Forgejo resource. Approved at that breadth on @@ -69,15 +69,27 @@ projection that only reads must not hold an identity that can write. ## Verify the lane (capabilities-safe — never read the value) ```bash -# Positive: the AppRole identity can read the data path -bao token capabilities platform/data/workloads/state-hub/forge-derivation +# Positive: the lane identity can read the data path +bao token capabilities platform/data/workloads/state-hub/forge-derivation # → expect: read # Negative: it can read nothing else, including the admin lane -bao token capabilities platform/data/workloads/forgejo/forgejo-admin +bao token capabilities platform/data/workloads/forgejo/forgejo-admin # → expect: deny ``` +Verified 2026-08-27 through a 2-minute test token, revoked after use: `read` on +its own path; `deny` on `forgejo-admin`, on the shared `llm-connect` provider +secrets, and on the parent metadata path (no listing). + +**Why Kubernetes auth and not an AppRole.** The construction plan proposed an +AppRole; the phase-4 live survey found `kubernetes/` auth already enabled on +this cluster, and the founder ruled for it on 2026-08-27. The pod authenticates +with its own projected ServiceAccount token, so this lane has no `role_id` +/`secret_id` pair to deliver, store, or rotate. The role binds to +`state-hub/state-hub` and deliberately **not** to `default`, which would grant +the lane to every pod in the namespace. + The negative check is the one that matters. The whole argument for building this lane instead of reusing `forgejo-admin-api-token` is that it cannot do what that one can.