key-cape/workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md

16 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 runtime workload identity infotech key-cape finished codex netkingdom 2026-07-23 2026-07-29 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/RMASTER-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

id: KEY-WP-0004-T01
status: done
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.

2026-07-27: IAM Profile v0.2 now preserves tenant:platform and tenant:coulomb as reserved ungrouped tenants and ratifies the external grouping vocabulary. The live service-token proof carries tenant:friendly:binky without platform authority.

Task: Provision bernd.worsch@binky-hedgehog.com as tenant-admin

id: KEY-WP-0004-T02
status: done
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.

2026-07-27 direction update: do not complete this through a one-shot operator script. USER-WP-0020 and NK-WP-0023 now own a reusable self-service and administration portal plus NetKingdom provisioning adapters. This task is their first production acceptance case.

The binky-hedgehog.com mailbox must exist and be reachable for account verification, but mailbox availability is now an input to the reusable registration flow rather than a manual provisioning procedure.

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.

2026-07-28: user-engine's deployed portal API created the tenant-admin membership and provisioned/linked the LLDAP identity through the reusable NetKingdom adapter. The identity is intentionally in password_setup_required; LLDAP has no SMTP configuration for its native reset delivery. First-password handoff, MFA enrollment, and final human-token claim/denial evidence remain. No operator-set password or raw credential was used as a shortcut.

2026-07-28 update: the reusable password handoff is now live at the canonical KeyCape host and is issued/renewed through the user-engine administration UI. Links are opaque, expire after 15 minutes, are single use, and older links are revoked on renewal. A disposable-user live test proved password registration, directory login, replay denial, and cleanup. This task now awaits only the Binky user's own password choice, MFA enrollment, and final scoped-token acceptance.

2026-07-29: the first portal attempt correctly denied cross-tenant access because KeyCape had not projected the established net-kingdom-admins group to the new platform-operator role. Commit 90a2078 adds and tests the explicit tenant:platform / platform-operator compatibility mapping and is deployed Ready. The operator must start a fresh OIDC session so the corrected claims are minted.

2026-07-29 human acceptance: the Binky administrator completed the reusable password setup, enrolled a privacyIDEA TOTP factor, and successfully signed in through KeyCape with password plus OTP. Enrollment revealed that privacyIDEA's default QR label exposed only the token serial. The live coulomb-friendly-token-labels enrollment policy now emits issuer Coulomb and label {user}@{realm} for future tokens; existing authenticator entries must be renamed locally because wallets do not accept remote label updates. The live token then carried tenant:friendly:binky, roles user and tenant-admin, only the Binky users/admins groups, and AAL2 assurance with pwd + otp and mfa: true. The same session was denied access to both tenant:platform and tenant:coulomb administration. Acceptance complete.

Task: Register a workload-identity OIDC client for the qonto runtime

id: KEY-WP-0004-T03
status: done
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.

2026-07-27: KEY-WP-0006 delivered rapp-qonto-client. Live exchange produced only the documented tenant, role, and qonto:read scope; wrong secret and excessive scope were denied.

Task: Route client_secret custody through secrets-engine + OpenBao

id: KEY-WP-0004-T04
status: done
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.

2026-07-27: Custody is established at platform/workloads/rapp-qonto/keycape-client, with runtime injection through sso/keycape-rapp-qonto-client. No raw value entered evidence or human handling.

Task: Register the credential lane with ops-warden

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

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.

2026-07-27: Published route rapp-qonto-keycape-client; route resolution and the metadata-only M3/prod posture check both pass.

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

id: KEY-WP-0004-T06
status: cancel
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

id: KEY-WP-0004-T07
status: done
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 (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 RMASTER-WP-0019. Run statehub fix-consistency.

2026-07-29 closure: T01T05 are complete, T06 is intentionally cancelled, the human Binky flow passed AAL2 and tenant-isolation acceptance, and the qonto workload client passed its positive-scope and negative credential/scope checks.