--- id: KEY-WP-0004 type: workplan title: "Binky Hedgehog GmbH as first NetKingdom tenant + qonto runtime workload identity" domain: infotech repo: key-cape status: active owner: codex topic_slug: netkingdom created: "2026-07-23" updated: "2026-07-26" state_hub_workstream_id: "ad6fa711-ba5b-4e7d-86e3-641f9acaf853" --- # Binky Hedgehog GmbH as first NetKingdom tenant + qonto runtime workload identity Binky Hedgehog GmbH ("binky") becomes the **first real tenant** provisioned in the NetKingdom IAM stack, per the NetKingdom IAM Profile v0.2's tenant claim model (`net-kingdom/canon/standards/iam-profile_v0.2.md` §"Tenant Claim") — distinct from `tenant:platform` (control plane) and `tenant:coulomb` (the ecosystem-development tenant this workstation already operates under). This closes **Gap #1** flagged in `qonto-assistant`'s `workplans/QONTO-WP-0003-mcp-surface.md` closure: no OIDC issuer existed anywhere in the fleet, so `qonto-assistant`'s MCP surface shipped with an interim shared-secret bearer token instead of real workload identity. `key-cape` is "Implementation complete (v0.1)" and already implements the profile's `client_credentials`/workload-identity grant for service accounts — it's the component that should close this gap, not `user-engine` (downstream user/profile data layer, not an identity provider) or `identity-canon` (terminology research only). **Depends on:** `key-cape` v0.1 (done, `KEY-WP-0001`), NetKingdom IAM Profile v0.2 tenant + service-account claim rules (already ratified canon — no new profile work needed, this is provisioning against an existing contract), and the cross-repo runtime direction now tracked in `railiance-master/workplans/RAILIANCE-WP-0019-knative-qonto-runtime-on-reef-railiance.md`. This workplan no longer targets a permanent direct `qonto-assistant` deployment shape. Its workload-identity lane is intended for the future `rapp-qonto` runtime on `rail-knative` hosted by `reef-railiance`, with current `qonto-assistant` consumption allowed only as a migration bridge until that package/rail path exists. ## Task: Confirm tenant identifier and provision the tenant plane ```task id: KEY-WP-0004-T01 status: todo priority: high state_hub_task_id: "ec65d1be-11cb-421f-84dd-f401206526fe" ``` **Decided 2026-07-23 (Bernd):** the IAM profile's `tenant:customer:` / `tenant:sandbox:` suggested identifiers name a tenant by **capability role** (customer, vendor, ...) — but tenants already known to hold multiple roles at once (see `net-kingdom/docs/princedom-isolation-exploration.md`'s unratified `PLTF`/`IAM`/`VEN`/`CUS` role model; Binky itself is both `CUS` and, later, `VEN`). Using a role word as the tenant *grouping* would collide with that separate role dimension. Decision: classify tenants by an onboarding-risk / entity-shape **grouping**, orthogonal to capability role: ```text trial — test/trial/showcase tenants only friendly — known, easily reached, tolerant of experimentation/instability single — one-person business entities (freelance consultants) small — up to 10 employees at time of onboarding (attoo) medium — up to 100 employees (attoo) large — up to 1000 employees (attoo) enterprise — 1001+ employees (attoo) consumer — private individuals family — a legal family community — a non-legal group of people association — a legal association of people agentic — financially enabled AI entities ``` `tenant::` replaces `tenant:customer:` / `tenant:sandbox:` as the identifier shape. **Binky maps to `friendly`** — known, reachable, tolerant of early instability — giving **`tenant:friendly:binky`** (slug matches the OpenBao path already in production, `tenants/binky/qonto-api`). **Open question, not yet resolved by this decision:** this grouping list classifies tenants as external-shaped entities: it has no obvious slot for `tenant:coulomb` itself (the platform's own internal/reference tenant, ADR-0006) — none of `trial`/`friendly`/`single`/.../`agentic` fit "the platform building itself." Confirm with Bernd whether `tenant:coulomb` stays an ungrouped special case (alongside `tenant:platform`) or gets folded into this scheme somehow, before treating the grouping list as complete. **Also open:** this is a fleet-wide vocabulary decision — the ratified `net-kingdom/canon/standards/iam-profile_v0.2.md` "Tenant Claim" section still documents the old `customer`/`sandbox` suggested identifiers, and NetKingdom owns that canon per ADR-0011. Recording this grouping list only in this key-cape workplan lets it drift from canon. Recommend a follow-up: either a decision record or an ADR in `net-kingdom` adopting this grouping list as the tenant-identifier standard, superseding the old suggested identifiers. Not drafted here — flagging so it isn't lost. Provision whatever tenant/org-unit boundary key-cape's current backend (LLDAP/Authelia) needs so tokens issued for subjects under this tenant correctly carry `tenant:friendly:binky` and nothing implies platform-root authority for it (profile rule: tenant administration for a tenant must never imply platform-root authority). Done when: `tenant:coulomb`'s place in the grouping scheme is resolved; the `net-kingdom` canon-update question above is answered (drafted or explicitly deferred); a test-subject token carries the `tenant:friendly:binky` claim. ## Task: Provision bernd.worsch@binky-hedgehog.com as tenant-admin ```task id: KEY-WP-0004-T02 status: todo priority: high state_hub_task_id: "b5cb4497-095c-4dd7-af31-831deddd422e" ``` Create the user in key-cape's current backend, enroll MFA per profile requirements (`assurance` claim, `net-kingdom/canon/standards/iam-profile_v0.2.md`), and assign a tenant-admin role/group scoped to `tenant:friendly:binky` only. **Prerequisite outside this repo's control:** the `binky-hedgehog.com` mailbox for `bernd.worsch@` must exist and be reachable for account verification and MFA enrollment. Flag to Bernd before starting — this task cannot complete without it. Done when: `bernd.worsch@binky-hedgehog.com` completes OIDC/PKCE + MFA login and receives a token carrying `tenant:friendly:binky` and a tenant-admin role claim; the same token does **not** grant access to `tenant:platform` or any other tenant. ## Task: Register a workload-identity OIDC client for the qonto runtime ```task id: KEY-WP-0004-T03 status: progress priority: high state_hub_task_id: "fbe9d2e0-7532-4403-8e12-947aa8fd0da7" ``` Register an OIDC client per the profile's service-account/workload-identity flow (`client_credentials` or the documented workload-token-exchange equivalent — §"Service Account Flow"), scoped to `tenant:friendly:binky`, with the minimum role/scope the qonto runtime surface actually needs. The intended steady-state consumer is the future `rapp-qonto` runtime on `rail-knative`; current `qonto-assistant` callers may use the same lane only as a documented migration bridge until that package split exists. No interactive login for this client — it's for agent-harness sessions and other automated callers, not humans. The resulting `client_secret` must never be pasted into chat, Git, this workplan, or a State Hub message or progress event — hand-off happens only through T04's secrets-engine/OpenBao lane. Done when: a `client_credentials` token exchange against key-cape succeeds for this client and produces a short-lived service token carrying `tenant:friendly:binky`; the `client_id`, granted scopes, and intended future binding to `rapp-qonto` are documented here; no secret material appears anywhere in this repo's history. 2026-07-26: Added `docs/qonto-runtime-identity-contract.md` with stable principal/client names, least-privilege claims, non-secret evidence, and the automation/custody boundary. Actual client issuance remains open. ## Task: Route client_secret custody through secrets-engine + OpenBao ```task id: KEY-WP-0004-T04 status: progress priority: high state_hub_task_id: "80901eb3-a959-49ab-bcde-01ddaafa8e59" ``` Coordinate with `secrets-engine` to create a scoped OpenBao lane for this `client_secret`, mirroring the existing `tenants/binky/qonto-api` pattern already in production use for the Qonto bank credential itself. The steady target is a dedicated future runtime role for `rapp-qonto`; if a temporary bridge via the current `qonto-assistant` runtime role is needed before the package split lands, it must be recorded as temporary rather than treated as the final contract. Done when: the intended qonto runtime role can fetch the `client_secret` via `secrets-engine`/OpenBao; any temporary `qonto-assistant` bridge is explicitly marked transitional; Bernd never handles the raw value at any point in this flow. 2026-07-26: `warden plan` classified first-time provisioning as one explicit founder authority act through `warden desk`. No secret was requested or read. All repeatable verification and revocation work is designated for sanctioned agent execution and later functional automation. ## Task: Register the credential lane with ops-warden ```task id: KEY-WP-0004-T05 status: progress priority: high state_hub_task_id: "a91326a6-f498-4569-a56b-95a49fe5794d" ``` This is the task that directly minimizes Bernd's ongoing engagement: add an entry to ops-warden's routing catalog (`registry/routing/catalog.yaml`) pointing at this new OIDC client / login lane, following the pattern already documented in `ops-warden/SCOPE.md`'s "Issue vs route" table ("Login / OIDC / MFA → key-cape / Keycloak → Assist — route; proxy `login` lane when `exec_capable`"). ops-warden does not mint tokens or take custody here — it routes/assists, same as every other credential lane it fronts. The lane should describe the future `rapp-qonto` runtime path on `rail-knative`, not only the current source repo. Once the OpenBao lane from T04 exists, run ops-warden's workload security posture conformance checker (`ops-warden/scripts/check_secret_posture_conformance.py`) against the qonto runtime workload that will later become `rapp-qonto`; until the split lands, `qonto-assistant` may be used as the migration subject if that temporary state is recorded. Confirm it meets the expected maturity tier (dev/test/prod posture, M0–M3 workload maturity) before this goes live with real credentials, and record the result (pass or documented exception). Done when: `warden route show` (or equivalent) resolves this lane correctly; posture conformance check passes or exceptions are explicitly recorded; from this point on, discovering and using this credential lane needs `warden access`, not direct key-cape/OpenBao admin knowledge. 2026-07-26: Routing requirements and required conformance evidence are now documented. Catalog publication waits for the real client and OpenBao role so the route does not advertise an unusable lane. ## Task: automation@binky-hedgehog.com service identity (deferred) ```task id: KEY-WP-0004-T06 status: todo priority: low state_hub_task_id: "d3460058-6e4c-426b-b575-1bbad192e40c" ``` Forward-looking per Bernd's framing ("I guess it will later be helpful") — **do not provision until a concrete automation workflow actually needs its own identity** distinct from the qonto runtime workload client from T03. Dormant service-account credentials are themselves a posture risk (unused attack surface, nothing to rotate against), so this stays parked rather than front-loaded. When a real consuming workflow exists: same pattern as T02 but scoped to an automation-appropriate role (not tenant-admin), likely paired with its own `client_credentials` registration for whichever agent/service authenticates as it, following T03/T04/T05's pattern rather than inventing a new one. Done when: explicitly triggered by a named consuming workflow — until then this task stays `todo` and does not block closing the rest of this workplan. ## Task: Closure review ```task id: KEY-WP-0004-T07 status: todo priority: low state_hub_task_id: "9511a7ef-0a04-45db-8a7b-598ab77ce737" ``` Mark workplan finished when T01–T05 are done (T06 may legitimately remain `todo`/parked by design — see its own task note). Confirm end to end: a human token (bernd.worsch@binky-hedgehog.com, tenant-admin) and a service token (future qonto runtime client, with any temporary `qonto-assistant` bridge explicitly recorded) both resolve to `tenant:friendly:binky` and nothing else; the credential lane is discoverable via `warden access` without Bernd touching key-cape/OpenBao admin surfaces directly. The runtime follow-up then continues in `QONTO-WP-0004` and `RAILIANCE-WP-0019`. Run `statehub fix-consistency`.