key-cape/workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md
tegwick df26aee844 KEY-WP-0004-T01: adopt tenant:<grouping>:<name> identifier, binky -> friendly
Bernd's decision: role words (customer/vendor) collide with the separate
capability-role dimension a tenant can hold (PLTF/IAM/VEN/CUS, per
net-kingdom/docs/princedom-isolation-exploration.md's unratified model --
Binky itself is both CUS and, later, VEN). Tenants are grouped instead by
onboarding-risk/entity-shape, orthogonal to role: trial, friendly, single,
small, medium, large, enterprise, consumer, family, community, association,
agentic.

Binky maps to friendly -> tenant:friendly:binky, replacing the earlier
tenant:customer:binky throughout this workplan.

Two open questions flagged, not resolved here: where tenant:coulomb (the
platform's own internal/reference tenant) fits this external-shaped grouping
list, and whether net-kingdom should ratify this list into
iam-profile_v0.2.md's Tenant Claim section, since it currently still
documents the old customer/sandbox suggested identifiers and NetKingdom
owns that canon per ADR-0011.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 15:45:43 +02:00

11 KiB
Raw Blame History

id type title domain repo status owner topic_slug created updated state_hub_workstream_id
KEY-WP-0004 workplan Binky Hedgehog GmbH as first NetKingdom tenant + qonto-assistant workload identity infotech key-cape ready codex netkingdom 2026-07-23 2026-07-23 ad6fa711-ba5b-4e7d-86e3-641f9acaf853

Binky Hedgehog GmbH as first NetKingdom tenant + qonto-assistant 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).

Downstream, not in this workplan: once T03/T04 land, qonto-assistant needs its own follow-up workplan to swap mcp_auth.BearerTokenAuthMiddleware for FastMCP's built-in TokenVerifier + AuthSettings(issuer_url=<key-cape>) against the client registered here. Tracked as a pointer only — not created by this workplan, since it's a different repo's scope and code change.

Task: Confirm tenant identifier and provision the tenant plane

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:<name> / tenant:sandbox:<name> 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:

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:<grouping>:<name> replaces tenant:customer:<name> / tenant:sandbox:<name> 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

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 qonto-assistant callers

id: KEY-WP-0004-T03
status: todo
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 qonto-assistant's MCP and REST surfaces actually need. 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 and granted scopes are documented here; no secret material appears anywhere in this repo's history.

Task: Route client_secret custody through secrets-engine + OpenBao

id: KEY-WP-0004-T04
status: todo
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 — so qonto-assistant's runtime fetches this the same way it already fetches the Qonto API key, via its own dedicated runtime role (qonto-assistant-runtime, per qonto-assistant/specs/ArchitectureBlueprint.md §4.7), not a shared or ad hoc role.

Done when: qonto-assistant's runtime role can fetch the client_secret via secrets-engine/OpenBao; Bernd never handles the raw value at any point in this flow.

Task: Register the credential lane with ops-warden

id: KEY-WP-0004-T05
status: todo
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.

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 new qonto-assistant workload to confirm it meets the expected maturity tier (dev/test/prod posture, M0M3 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.

Task: automation@binky-hedgehog.com service identity (deferred)

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-assistant 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

id: KEY-WP-0004-T07
status: todo
priority: low
state_hub_task_id: "9511a7ef-0a04-45db-8a7b-598ab77ce737"

Mark workplan finished when T01T05 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 (qonto-assistant workload client) 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. Note the qonto-assistant-side follow-up workplan (swap bearer token for TokenVerifier) as the next step, out of this workplan's scope. Run statehub fix-consistency.