railiance-platform/docs/credential-lane-designs/fluid-telegram-operator-kv.md
codex 193b1276f3 Document credential lane designs and adopt fast projection sync
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a06ecb-456a-71c2-b41e-0755d336e883
2026-09-05 10:41:56 +02:00

101 lines
5.8 KiB
Markdown

# Fluid-telegram attended operator KV lane
Status: proposed, not provisioned. Owner: railiance-platform, RPF-WP-0033.
Demand: State Hub message `170b9127-f18f-4045-8f64-5c211a3aa187`.
Construction reference: `../ops-mason/plans/fluid-telegram-operator-credential-lane.md`.
Consumer source: `../fluid-telegram/internal/secrets/secrets.go`, `session.go`
and `internal/apply/apply.go`.
## Proposed coordinates
Use KV-v2 mount `platform`, proposed campaign prefix
`workloads/coulomb/fluid-telegram/hall-of-helix`. The organisation/tenant
precedent is CCR-2026-0001, not the consumer's State Hub domain `infotech`.
This is the platform design recommendation; tenant ownership is still an
explicit activation gate. Set `FLUID_BAO_PREFIX` to the mount-relative prefix,
without `platform/` or `data/`. The current client defaults to `infotech` and
its comment claims owner confirmation that the construction plan does not
contain; the client/docs must be corrected once the tenant decision is accepted.
Propose policy `workload-kv-fluid-telegram-hall-of-helix-operator` and OIDC role
`fluid-telegram-hall-of-helix-workload-kv` under `auth/netkingdom`. Bind the
actual owner-confirmed `groups` claim. `fluid-telegram-operators` is only a
candidate name; it must not become a live binding without KeyCape/NetKingdom
evidence and membership approval. Require an attended human identity and the
owner's MFA requirement; group membership alone is not proof of MFA.
Token TTL `15m`, maximum and explicit maximum `30m`, no default policy,
no periodic token. Do not choose a finite use count without measuring the
session writer; propose `token_num_uses=0` within that short lifetime to avoid
interrupting MTProto session persistence. Self-revoke at completion with an
explicit `auth/token/revoke-self` update grant. OIDC scopes are
`openid,profile,email,groups`, user claim `sub`, groups claim `groups`.
Approve exact private/operator callback URIs with the provider; reuse verified
localhost/127.0.0.1 CLI callbacks. Do not add a public Bao UI callback merely
because old CCRs contain it while RPF-WP-0025 retracts that listener.
## Exact data scope
Let `P = platform/data/workloads/coulomb/fluid-telegram/hall-of-helix`.
Each row is a literal path; there is no wildcard or parent listing.
| Path | Fields used by current client | Capabilities |
| --- | --- | --- |
| `P/operator-app` | `api_id`, `api_hash` | read |
| `P/operator-session` | `session_b64` | create, read, update |
| `P/bot-token` | `token` | create, read, update |
| `P/redaction-salt` | `salt` | create, read |
No metadata access, patch, delete, undelete, destroy, list or sudo is granted.
The KV ACL governs an entry, not individual fields: the builder must not mix
unrelated material into these entries. Operator-app is seeded through an
independent approved attended write path. The provisioner owns session/token
writes. The future adapter receives its own read-only bot-token/salt lane and
never the session or operator-app credential.
Add exact coding-agent boundary denies on all four data and metadata paths
before activation, and test the effective union of identity policies. The
provisioner currently accepts ambient tokens and `~/.vault-token`; its attended
wrapper must explicitly select the bounded role and avoid silently using an
old broader operator token. Cleanup must not delete an unrelated token sink.
## Required tooling change
Propose a new CCR request type `workload-kv-operator-matrix`, not a reinterpretation
of `workload-kv-read`. Its schema must require confirmed tenant, campaign,
group claim, per-entry exact path/fields/capabilities, issuer/MFA evidence,
reviewers, callback list, token bounds, boundary deny targets and lifecycle.
Its validator must enforce this approved matrix, reject wildcard/parent paths,
unknown capabilities, duplicate/escaping paths and unconfirmed bindings.
The renderer/applier must reject this type until implemented; existing read-only
CCR validation must continue unchanged. ops-mason also needs an OIDC role writer
and per-path policy renderer with a reviewable mutation plan and exact scope.
No direct policy/role write bypass is authorized by this design.
`CreateIfAbsent` currently does GET then ordinary POST. Require the salt write
to use KV-v2 `options.cas=0`; concurrent losers reread the winning salt and must
not overwrite it. Test this against the installed engine with a disposable
probe entry under separately approved probe scope, never by granting wildcard
access to production. OpenBao documents distinct create/update ACLs and CAS
zero semantics in its [KV-v2 guide](https://openbao.org/docs/secrets/kv/kv-v2/).
Do not try to enforce field names or CAS using KV-v2 ACL parameter restrictions;
the guide says those parameter filters are unsupported.
## Approval, verification and lifecycle
Platform and consumer accept tenant/path; IAM owner confirms group and MFA;
ops-mason/platform review matching CCR and executor changes; an attended
operator approves exact objects and value-entry window after a live survey.
Activation requires positive matrix checks, wrong-group and agent denial,
sibling campaign/workload denial, salt first-write success/second-write denial,
concurrent CAS behavior, and safe error/cleanup tests. Replace preflight output
that currently prints an `api_id` prefix with a boolean presence result.
Session compromise requires Telegram-side session revocation, not just Bao
token revocation. Bot-token rotation requires provider replacement and consumer
verification. Salt rotation changes longitudinal pseudonyms and requires an
explicit data-owner decision; never rotate it as routine teardown. Disabling
the role stops new sessions but existing tokens need revocation or TTL expiry.
Keep KV versions in custody pending retention decisions; rollback disables the
role/policy without deleting values. Publish the routing pointer only after
all verification and owner receipts are complete.