Plan status approved (Bernd Worsch, 2026-10-09) with build_spec and approved_spec_sha256 41a0ca27; the executor's approval gate accepts it. T04 now waits on the founder-run applier (RPF-WP-0035-T03, decision 62aa95e4). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 327203@bnt-lap001 Assistant-Session: 55028ae3-4914-4bd1-8f5c-815f3527aef0
292 lines
14 KiB
Markdown
292 lines
14 KiB
Markdown
---
|
|
id: fluid-telegram-operator-credential-lane
|
|
demand_source: fluid-telegram/workplans/FT-WP-0002 and State Hub message 287cf897-7f47-4bcc-87d6-085f43d5f03e
|
|
consumer_repo: fluid-telegram
|
|
credential_type: openbao-oidc-kv-read-write
|
|
status: approved
|
|
approved_by: "Bernd Worsch"
|
|
approved_at: "2026-10-09"
|
|
approved_spec_sha256: "41a0ca2746aa93b6ee9d1ca631517d680ade95c56e7a38b75a55209ef2316b73"
|
|
created: "2026-09-04"
|
|
updated: "2026-10-09"
|
|
build_spec:
|
|
engine: openbao-oidc-kv-read-write
|
|
policy_name: workload-kv-fluid-telegram-hall-of-helix-operator
|
|
role_name: fluid-telegram-hall-of-helix-workload-kv
|
|
campaign_path: platform/workloads/coulomb/fluid-telegram/hall-of-helix
|
|
bound_group: fluid-telegram-operators
|
|
allowed_redirect_uris:
|
|
- http://localhost:8250/oidc/callback
|
|
- http://127.0.0.1:8250/oidc/callback
|
|
- http://127.0.0.1:18200/ui/vault/auth/netkingdom/oidc/callback
|
|
identity_confirmation_ref: key-cape message b2ed890f (key-cape e0b5fae); LLDAP group
|
|
fluid-telegram-operators exists, member tegwick (founder 2026-10-09)
|
|
platform_matrix_review_ref: railiance-platform docs/credential-lane-designs/fluid-telegram-operator-kv.md
|
|
(matrix identical, checked 2026-10-09)
|
|
auth_mount: netkingdom
|
|
token_ttl: 15m
|
|
token_max_ttl: 30m
|
|
bao_bin: bao
|
|
audit_log_path: /home/worsch/ops-mason/audit/build-log.jsonl
|
|
---
|
|
|
|
# Construction plan: fluid-telegram operator credential lane
|
|
|
|
## 1. Demand
|
|
|
|
`fluid-telegram` has an attended provisioner that creates a Telegram bot and
|
|
channels from a declared campaign specification. The provisioner needs an
|
|
operator OIDC token that reads four campaign-specific KV entries, writes the
|
|
MTProto session and bot token, and creates the redaction salt once. The
|
|
MTProto session is a full-account credential, so this is a high-risk operator
|
|
lane, never an autonomous agent or adapter lane. ops-mason constructs only the
|
|
OpenBao structure and never handles Telegram values.
|
|
|
|
The first consumer is campaign `hall-of-helix`. A future adapter has a
|
|
different, narrower need and is intentionally excluded from this plan.
|
|
|
|
## 2. Existing-structure survey
|
|
|
|
### Disk survey completed 2026-09-04
|
|
|
|
- `railiance-platform/docs/workload-kv-access-lanes.md` documents attended
|
|
OIDC through `auth/netkingdom`, exact group-bound roles, three callback URIs,
|
|
and 15-minute tokens.
|
|
- The nearest concrete tenant-shaped path is
|
|
`platform/workloads/coulomb/whynot-design/npm-publish`. Its CCR history says
|
|
the owner corrected the first segment to the organisation/tenant, not the
|
|
State Hub domain.
|
|
- Existing policy files contain no `fluid-telegram` lane.
|
|
- `ops-warden/registry/routing/catalog.yaml` contains only the generic
|
|
`openbao-api-key` template for this need, and its login string omits
|
|
`-path=netkingdom`. No concrete Telegram lane exists.
|
|
- `ops-mason/src/ops_mason/executor.py` supports AppRole and Kubernetes KV
|
|
lanes. It has no OIDC role writer and its generic policy helper emits the
|
|
same capabilities for one data and metadata path, which cannot express this
|
|
four-path matrix.
|
|
- `railiance-platform/schemas/credential-change-request.schema.yaml` permits
|
|
only `request_type: workload-kv-read`; its validator also requires the
|
|
`workload-kv-read-` policy prefix and `-workload-kv-read` OIDC role suffix.
|
|
|
|
### Live survey (2026-10-08)
|
|
|
|
Generated by `scripts/plan-survey.py` at 2026-10-08T21:53:55Z against `BAO_ADDR=http://127.0.0.1:18200`, token display_name `token-claude-MASON-WP-0005-T01` (policies: default, ops-mason-survey). Metadata only: no `kv get` and no `*/data/*` read was issued; policy bodies were read with `bao policy read` for name-matched candidates only.
|
|
|
|
Demand: KV path `platform/workloads/coulomb/fluid-telegram/hall-of-helix`, proposed policy `workload-kv-fluid-telegram-hall-of-helix-operator`, AppRole `-`, Kubernetes role `-`, consumer `fluid-telegram`. Match terms: `fluid-telegram`, `hall-of-helix`, `telegram`, `coulomb`.
|
|
|
|
#### `bao secrets list` (10 mounts, 1 relevant)
|
|
|
|
```text
|
|
platform/ kv version=2
|
|
```
|
|
|
|
#### `bao auth list` (5 auth mounts, 2 relevant)
|
|
|
|
```text
|
|
approle/ approle
|
|
kubernetes/ kubernetes
|
|
```
|
|
|
|
#### `bao policy list` (81 policies, 0 relevant)
|
|
|
|
```text
|
|
(no relevant entries)
|
|
```
|
|
|
|
#### `bao list auth/approle/role` (approle) (14 roles, 0 relevant)
|
|
|
|
```text
|
|
(no relevant entries)
|
|
```
|
|
|
|
#### `bao list auth/kubernetes/role` (kubernetes) (27 roles, 0 relevant)
|
|
|
|
```text
|
|
(no relevant entries)
|
|
```
|
|
|
|
#### `bao policy read` of name-matched candidates (target `platform/data/workloads/coulomb/fluid-telegram/hall-of-helix`)
|
|
|
|
```text
|
|
(no relevant entries)
|
|
```
|
|
|
|
#### `bao kv metadata get` / `bao kv list` (metadata only)
|
|
|
|
```text
|
|
platform/workloads/coulomb/fluid-telegram/hall-of-helix: no metadata (path unused)
|
|
platform/workloads/coulomb/fluid-telegram/: request failed (output suppressed)
|
|
```
|
|
|
|
#### ops-warden routing catalog `/home/worsch/ops-warden/registry/routing/catalog.yaml` (42 entries, 4 relevant)
|
|
|
|
```text
|
|
whynot-design-npm-publish owner=railiance-platform status=active matches: coulomb
|
|
path_template: platform/workloads/coulomb/whynot-design/npm-publish
|
|
policy_ref: flex-auth check secret.read:whynot-design
|
|
auth_method: bao login -method=oidc -path=netkingdom role=whynot-design-workload-kv-read
|
|
reuse-surface-hub-write-token owner=railiance-platform status=active matches: coulomb
|
|
path_template: platform/workloads/reuse/reuse-surface/runtime-secrets
|
|
policy_ref: flex-auth check secret.read:reuse
|
|
auth_method: caller's own OpenBao token (operator OIDC via key-cape, or a token carrying workload-kv-read-reuse-surface-runtime)
|
|
inbound-library-imap-approle owner=ops-mason status=active matches: coulomb
|
|
path_template: platform/workloads/inbound-library/imap
|
|
auth_method: AppRole login role=inbound-library (role_id+secret_id in ~/.local/inbound-library/approle, config/library.json credential.approle_dir)
|
|
coulomb-social-runtime-env owner=railiance-platform status=active matches: coulomb
|
|
path_template: k8s:coulomb-social/coulomb-social-env
|
|
auth_method: kubectl as platform operator (or bao OIDC when OpenBao lane is provisioned)
|
|
```
|
|
|
|
#### Does an existing lane already satisfy this demand?
|
|
|
|
**Draft answer: no.** Review before committing; this is generated, not a decision.
|
|
|
|
- no surveyed policy grants `platform/data/workloads/coulomb/fluid-telegram/hall-of-helix`, the proposed names are free, the KV path is unused and no catalog entry routes it
|
|
- policy grants were checked only for name-matched candidates; a policy with an unrelated name that covers `platform/data/workloads/coulomb/fluid-telegram/hall-of-helix` is not detected
|
|
|
|
|
|
#### Additions by hand (same grant)
|
|
|
|
- `bao list auth/netkingdom/role` (12 roles): no `fluid-telegram*` role; the
|
|
proposed `fluid-telegram-hall-of-helix-workload-kv` is free. The generator
|
|
did not flag the `netkingdom` OIDC mount as relevant; it is the one this lane
|
|
reuses.
|
|
- All 81 policy bodies scanned (closing the generator's name-match gap): only
|
|
`platform-admin` (`platform/*`) covers the target. No workload policy does.
|
|
- Live reference role `keycape-secrets-engine-openbao-operator-workload-kv-read`
|
|
has exactly the binding this plan renders: `bound_claims_type=string`,
|
|
`bound_claims={groups:[net-kingdom-admins], /assurance/level: aal2}`,
|
|
`groups_claim=groups`, `token_no_default_policy=true`. The executor's role
|
|
document matches that shape.
|
|
- Naming: live OIDC roles end `-workload-kv-read` and their policies start
|
|
`workload-kv-read-`. This lane writes, so it drops `-read`
|
|
(`workload-kv-fluid-telegram-hall-of-helix-operator`); that is why the CCR
|
|
schema extension (T02) is needed.
|
|
|
|
**Existing-lane answer: none.** Confirmed live: path unused, names free, no
|
|
covering workload policy, no catalog route.
|
|
|
|
### OIDC role shape
|
|
|
|
- auth mount: `netkingdom`
|
|
- role: `fluid-telegram-hall-of-helix-workload-kv`
|
|
- token policies: exactly
|
|
`workload-kv-fluid-telegram-hall-of-helix-operator`; set
|
|
`token_no_default_policy=true`
|
|
- role type: `oidc`
|
|
- token TTL: `15m`, maximum TTL `30m`
|
|
- user claim: `sub`; groups claim: `groups`
|
|
- scopes: `openid,profile,email,groups`
|
|
- bound claims (`bound_claims_type=string`): `groups=[fluid-telegram-operators]`
|
|
and `/assurance/level=aal2` — confirmed by key-cape 2026-10-08 (message
|
|
`b2ed890f-a05a-4b96-95eb-2cd9d8b32caa`, key-cape `e0b5fae`). Human ID tokens
|
|
always carry `groups` (LLDAP group names); `aal2` is set only after a
|
|
verified privacyIDEA factor, the same pin as CCR-2026-0034.
|
|
- precondition met: LLDAP group `fluid-telegram-operators` exists with the
|
|
single member `tegwick` (founder report 2026-10-09, created in the LLDAP admin
|
|
UI; names only).
|
|
- callbacks (subset of the `openbao-admin` client registration):
|
|
`http://localhost:8250/oidc/callback`, `http://127.0.0.1:8250/oidc/callback`,
|
|
`http://127.0.0.1:18200/ui/vault/auth/netkingdom/oidc/callback`. Never the
|
|
retired `https://bao.coulomb.social/...` (2026-09-15).
|
|
|
|
The role is campaign-specific because its policy is campaign-specific. A
|
|
second campaign receives a second policy and role after its own review; it is
|
|
not added below this prefix.
|
|
|
|
### Value flow
|
|
|
|
- An attended operator enters `operator-app` with the existing sanctioned
|
|
paste-once/value-entry mechanism.
|
|
- The provisioner creates or updates `operator-session` and `bot-token`.
|
|
- The provisioner creates `redaction-salt` once.
|
|
- ops-mason records paths, policy/auth metadata, capabilities, versions,
|
|
timestamps, and audit references only. It never requests or reads a value.
|
|
|
|
## 4. Review notes (phase 2)
|
|
|
|
Complete as of 2026-10-09 (T01 and T02 done); plan moved to `reviewed`.
|
|
|
|
- **Reuse:** reuse the existing `netkingdom` auth mount, callback set, group
|
|
claim pattern, 15-minute TTL, and KV-v2 mount. Create only the policy and
|
|
role that do not exist.
|
|
- **Least privilege:** exact entry paths are safer than one campaign-prefix
|
|
wildcard and are necessary for the salt's create-only rule. The role has no
|
|
access to KV metadata because the provisioner uses data GETs to detect
|
|
absence; metadata evidence comes from the separately scoped builder/operator
|
|
verification path.
|
|
- **Identity binding:** group and assurance claims confirmed by key-cape; the
|
|
group exists with one member. Membership is the whole access decision, so
|
|
adding a member later is a change to this lane's reach.
|
|
The role must not be readable by every OIDC user.
|
|
- **Write-once semantics:** KV-v2 create/update distinction is documented, but
|
|
activation also requires an owner-run non-secret probe proving the installed
|
|
engine behaves as expected. The resulting evidence contains no probe value.
|
|
- **Agent boundary:** explicit denies must cover all four data paths and their
|
|
metadata paths. The operator-session path is the decisive negative check.
|
|
- **Adapter separation:** `MASON-IN-0003` tracks a later runtime lane that
|
|
reads only `bot-token` and `redaction-salt`; no role or policy in this plan is
|
|
reused by the adapter.
|
|
- **Reversal:** disable/delete the OIDC role first, then retire the policy. KV
|
|
entries remain in operator custody for an explicit retention/recovery
|
|
decision; teardown does not silently delete values.
|
|
- **Platform matrix:** railiance-platform's
|
|
`docs/credential-lane-designs/fluid-telegram-operator-kv.md` carries the same
|
|
four paths and capabilities as `_OPERATOR_MATRIX` in
|
|
`src/ops_mason/executor.py` (checked 2026-10-09).
|
|
- **Implementation gates:** both ops-mason and railiance-platform must extend
|
|
their current read-lane tooling before construction. Direct `bao policy
|
|
write`/`bao write auth/netkingdom/role/...` commands outside those approved
|
|
surfaces are not an alternative.
|
|
|
|
### Verification required before routing activation
|
|
|
|
1. Positive capabilities on each exact path match the matrix above.
|
|
2. Parent, sibling workload, and sibling campaign paths report `deny`.
|
|
3. A non-member OIDC identity cannot obtain the role's policy.
|
|
4. Agent-bound identities report `deny` on all four data and metadata paths.
|
|
5. An owner-run disposable KV-v2 probe proves create succeeds and a second
|
|
write with the same policy is denied; only timestamps, versions, path, and
|
|
pass/fail are returned.
|
|
6. The value-entry/provisioner flow confirms all required entries exist using
|
|
metadata/version evidence only.
|
|
7. ops-warden keeps `fluid-telegram-operator` non-resolvable until all checks
|
|
pass and the exact built pointers are returned.
|
|
|
|
## 5. Executive summary (phase 3)
|
|
|
|
**What this creates.** One OpenBao policy and one sign-in role, nothing else:
|
|
|
|
- policy `workload-kv-fluid-telegram-hall-of-helix-operator`: on
|
|
`platform/data/workloads/coulomb/fluid-telegram/hall-of-helix/`
|
|
`operator-app` read; `operator-session` and `bot-token` create, read, update;
|
|
`redaction-salt` create, read (write-once); plus revoke-self. No metadata,
|
|
list, parent or sibling access.
|
|
- OIDC role `fluid-telegram-hall-of-helix-workload-kv` on the existing
|
|
`auth/netkingdom` mount: only members of `fluid-telegram-operators`
|
|
(today: `tegwick`) with a verified second factor (`aal2`); 15-minute token,
|
|
30 minutes at most; no default policy; the two loopback CLI callbacks and the
|
|
operator-tunnel UI callback.
|
|
|
|
**Why it is safe.** The MTProto session is a full-account Telegram credential,
|
|
so the lane is attended only: a person with MFA, never an agent or the future
|
|
adapter. The path is unused and no workload policy reaches it today (live
|
|
survey 2026-10-08). ops-mason writes only the policy and role; no value passes
|
|
through it, and the salt cannot be overwritten.
|
|
|
|
**What approval also accepts.** The tenant segment `coulomb` (replacing the
|
|
consumer's `infotech` assumption), and the exact matrix above, which
|
|
railiance-platform's lane design already matches.
|
|
|
|
**What happens after approval.** The structure is applied through the approved
|
|
surfaces only (railiance-platform's per-path applier, RPF-WP-0035-T03, under the
|
|
attended provisioning decision `62aa95e4`; ops-mason's
|
|
`build_oidc_kv_lane`), never by direct `bao` writes. ops-warden's
|
|
`fluid-telegram-operator` entry stays non-resolvable until the seven checks
|
|
above pass, including the owner-run write-once probe.
|
|
|
|
**Undo.** Delete the role, then the policy. Stored values stay in operator
|
|
custody until someone decides their retention explicitly.
|
|
|
|
To approve, the founder says "APPROVE fluid-telegram-operator-credential-lane";
|
|
ops-mason then sets `status: approved`, `approved_by` and `approved_at`.
|