ops-mason/plans/reuse-surface-hub-writer.md
tegwick fca5591bc6 MASON-WP-0012: named-role login without session reuse, diagnosis receipt, capabilities-self proof (NK-WP-0051-T06)
verify-reuse-surface-hub-writer.py logs in with skip_browser=true and
shows the address (or opens a fresh temporary browser profile), so the
default Authelia session is never reused. The receipt records uid,
openbao_error and assurance per net-kingdom/docs/sign-in-diagnosis.md,
with tokens, codes and emails redacted. Capabilities come from
sys/capabilities-self on the lane token; no operator or root token is
read. Needs railiance-platform CCR-2026-0045 applied to run live.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1041694@bnt-lap001
Assistant-Session: 7af0bb68-ac4a-4ce3-8639-24ddd84c0b52
2026-10-14 23:48:11 +02:00

9.3 KiB

id demand_source consumer_repo credential_type status approved_by approved_at created updated filed_as
reuse-surface-hub-writer the-custodian/workplans/CUST-WP-0081 and State Hub message 08b254af-59d4-4d1a-9544-fed3dcaaf213 reuse-surface openbao-oidc-kv-read draft null null 2026-10-14 2026-10-14 CCR-2026-0044

Construction plan: dedicated reuse-surface hub-writer caller

1. Demand

CUST-WP-0081 needs to register reviewed capabilities at the reuse-surface hub. The write bearer already exists at platform/workloads/reuse/reuse-surface/runtime-secrets, field REUSE_SURFACE_TOKEN, delivered to the hub by External Secrets under CCR-2026-0005. warden access reuse-surface-hub-write-token --exec is the attended fetch. On 2026-10-14 that fetch returned OpenBao HTTP 403 after flex-auth decision decision:f730e3da14beebdd. The helper did not run.

The operator then confirmed OpenBao CLI entity 4a1f663c-0621-0483-edd0-f852274f4b6b carries default, operator-custody and platform-admin. bao token capabilities on that token reports create, delete, list, read and update on the exact data path, the exact metadata path, and an unrelated sibling. That token is not a dedicated caller. OpenBao adds entity policies to every token for the entity, so attaching workload-kv-read-reuse-surface-runtime to this entity would not produce a token that carries only that policy. The request forbids that attachment and forbids sending any secret value.

2. Existing-structure survey

Live plan-survey.py was not run. There is no ops-mason-survey grant in this session, and the admin token must not be used as the survey credential. This section is from the repositories on disk at 2026-10-14.

  • Policy workload-kv-read-reuse-surface-runtime (railiance-platform/openbao/policies/workload-kv-read-reuse-surface-runtime.hcl) grants read on the exact data path and the exact metadata path. It grants nothing else. Sibling denial is the absence of any other grant. No auth role in railiance-platform names this policy.
  • ESO uses the separate policy workload-kv-read-reuse-surface-runtime-eso and Kubernetes role reuse-surface-runtime-eso (CCR-2026-0005, updated 2026-09-05). That lane is the hub pod's delivery path, not the workstation caller.
  • agent-high-risk-boundary denies data read and allows metadata read on this path for tokens that carry it. platform-admin grants platform/*. A token with both would be denied on the data path, because deny wins. The reported capability set does not include deny, so the 403 and the capability report are not the same effective token. The verifier must measure the token that warden access will actually use.
  • Catalog entry reuse-surface-hub-write-token is active and resolvable: true. Its auth_method says the caller's own OpenBao token, either operator OIDC or a token carrying the workload policy. It does not name a role or an entity. CCR-2026-0005 does not name one either.
  • Redirects that use https://bao.coulomb.social are stale. The public ingress is gone. Fluid-telegram's role uses localhost, 127.0.0.1:8250, and the 127.0.0.1:18200 tunnel.

Does an existing lane already satisfy this demand? The KV path and the read policy do. The caller binding does not. The change is a role bound to a different principal, plus the two self-lifecycle stanzas the platform generator emits for token_self_lifecycle: true. No new secret, no new KV path, no change to the ESO role.

3. Proposed changes

SEC-DSM §37, in order:

  • Q1. The hub still requires its existing bearer. Reading that bearer from OpenBao can use a person or service identity. Do not create a secret to stand in for the caller.
  • Q2. OpenBao accepts OIDC on auth/netkingdom. Use that. A KeyCape group selects the principal. The principal's OpenBao entity must not be 4a1f663c-0621-0483-edd0-f852274f4b6b and must not carry platform-admin or operator-custody. The uuid f94b7c34-e151-30bb-b473-df3ccdbb9bf1 is not an OpenBao entity.
  • Q3. The OpenBao token is a 15-minute service token from the role. The hub bearer stays the static field already in KV. No new issuance layer.
  • Q4. Rotation of the hub bearer stays CCR-2026-0005. This plan does not rotate it.
  • Q5. No new persistent secret. Owner of the binding is railiance-platform. The consumer is the attended hub-registration helper. Authority is the OIDC role. Delivery is warden access --exec with the lane token. Revocation is auth/token/revoke-self and deletion of the role.

Preference hierarchy: federated identity for the read, existing vaulted static bearer for the hub. Not a new static secret and not a new AppRole.

  1. modify policy workload-kv-read-reuse-surface-runtime. Add auth/token/lookup-self read and auth/token/revoke-self update. Leave the two KV paths as read. Do not add a glob deny: in OpenBao a deny on a prefix also denies the more specific path. Sibling denial remains "not granted", checked on a parent path and on platform/data/workloads/issue-core/issue-core/issue-core-runtime.
  2. create OIDC role auth/netkingdom/role/reuse-surface-hub-writer-workload-kv-read. token_policies is only the workload policy, token_no_default_policy is true, TTL 15m, max 30m, group reuse-surface-hub-writers, assurance aal2. Callbacks are the workstation URIs above.
  3. create KeyCape group reuse-surface-hub-writers with member bernd.worsch-3. The OpenBao entity is created on first login. The member receipt rejects the admin entity and any token that also carries platform-admin or operator-custody.
  4. No KV write. No attachment of this policy, or of workload-kv-read-reuse-surface-runtime-eso, to entity 4a1f663c-0621-0483-edd0-f852274f4b6b.

Artifacts: builds/reuse-surface-hub-writer/. The CCR id is a draft. railiance-platform assigns the real id and applies it. ops-mason does not install the policy or the role.

4. Review notes

The 403 is not evidence that the path is closed to every token. It is evidence that the token warden access used could not read the field. The later capability check describes a different, broader token. The member receipt has to show both facts on one token: exact policy set, and deny on a sibling. A pass on the admin entity is a failure.

credential-change.py will not keep a hand-written sys/capabilities-self stanza. The verifier therefore asks sys/capabilities with the operator token and puts the lane token only in a mode-0600 body file that it deletes. The receipt never contains the token.

Superseded by NK-WP-0051-T06 (MASON-WP-0012): railiance-platform now generates the grant from openbao.token_capabilities_self (CCR-2026-0045), and the verifier calls sys/capabilities-self with the lane token only.

Catalog reuse-surface-hub-write-token stays active. This plan does not ask ops-warden to vend the value. After both verifier modes pass, ops-warden can name the role in auth_method. Until then the entry's caller is unnamed and the draft front door stays pending-review.

5. Attended apply and proof

Founder, after platform-operator and reuse-surface-owner approval, and after key-cape confirms the group:

  1. Copy the policy file over railiance-platform/openbao/policies/workload-kv-read-reuse-surface-runtime.hcl and apply the CCR with the delegated applier. Do not run bao kv put.
  2. The capability query uses the first local token allowed to call sys/capabilities: BAO_TOKEN or VAULT_TOKEN, then ~/.local/openbao/platform-admin.token, then ~/.vault-token. In a private window, as the group member:
python3 scripts/verify-reuse-surface-hub-writer.py member
python3 scripts/verify-reuse-surface-hub-writer.py non-member
  1. Receipts are mode 0600 under ~/.local/state/railiance/receipts/reuse-surface-hub-writer-*.txt. Copy the sanitized text into docs/evidence/ only after both results are pass. That copy is the verification receipt. It is not written in advance.
  2. Reply to message 08b254af with the receipt text. Then a registration command may use the same role's unprinted token:
warden access reuse-surface-hub-write-token --exec --field REUSE_SURFACE_TOKEN -- <silent helper>

Set BAO_TOKEN to the lane token for that one command. Do not use --fetch. Do not export the field. Revoke the lane token when the command returns.

6. Result

Applied 2026-10-14T17:47:43Z. Both attended receipts passed on 2026-10-14. Member at 20:05:45Z is entity c204099b-cb94-363f-e207-5ff4d4aa6e94 with only workload-kv-read-reuse-surface-runtime. Non-member at 20:10:49Z was refused. Copies are in docs/evidence/2026-10-14-reuse-surface-hub-writer-member.txt and docs/evidence/2026-10-14-reuse-surface-hub-writer-non-member.txt.

2026-10-14: railiance-platform filed this bundle as proposed CCR-2026-0044 (88b4aed, message 14e23602). The live policy file stays as it was until apply. The founder created LLDAP group reuse-surface-hub-writers with member bernd.worsch-3. On 2026-10-14 that user enrolled a second factor. tegwick is not the member. The founder reported uuid f94b7c34-e151-30bb-b473-df3ccdbb9bf1. OpenBao has no entity with that id and no entity named bernd.worsch-3. CCR-2026-0044 is approved in railiance-platform 8655857, with the group and aal2 binding confirmed. A passing login still has to present /assurance/level=aal2.