Draft KEY-WP-0004: Binky Hedgehog GmbH as first tenant + qonto-assistant workload identity
Provisions the first real NetKingdom tenant (tenant:customer:binky, matching the slug already live in production OpenBao paths) with a human tenant-admin user and a workload-identity OIDC client for qonto-assistant's MCP callers, routed through secrets-engine for secret custody and ops-warden for discoverable, minimal-touch credential access. Closes Gap #1 flagged in qonto-assistant's QONTO-WP-0003 closure (no OIDC issuer existed in the fleet). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
1a7fdadcda
commit
b9a7d1b008
1 changed files with 206 additions and 0 deletions
206
workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md
Normal file
206
workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
---
|
||||
id: KEY-WP-0004
|
||||
type: workplan
|
||||
title: "Binky Hedgehog GmbH as first NetKingdom tenant + qonto-assistant workload identity"
|
||||
domain: infotech
|
||||
repo: key-cape
|
||||
status: ready
|
||||
owner: codex
|
||||
topic_slug: netkingdom
|
||||
created: "2026-07-23"
|
||||
updated: "2026-07-23"
|
||||
---
|
||||
|
||||
# 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
|
||||
|
||||
```task
|
||||
id: KEY-WP-0004-T01
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
The IAM profile's tenant identifiers (`tenant:platform`, `tenant:coulomb`,
|
||||
`tenant:sandbox:<name>`, `tenant:customer:<name>`) are documented as
|
||||
*suggested*, not exhaustive — but `tenant:customer:<name>` is the closest fit
|
||||
for the first real operating/customer-plane tenant, distinct from the
|
||||
`tenant:coulomb` ecosystem-development plane.
|
||||
|
||||
**Recommended default, to confirm before implementing:** `tenant:customer:binky`
|
||||
— matching the slug already live in production OpenBao paths
|
||||
(`tenants/binky/qonto-api`, used by `qonto-assistant` today) rather than
|
||||
`tenant:customer:binky-hedgehog`, to avoid a slug mismatch between the new
|
||||
IAM tenant claim and the existing secret-custody path convention. Flag to
|
||||
Bernd for explicit confirmation before provisioning — tenant identifiers are
|
||||
expensive to rename once tokens and downstream config reference them.
|
||||
|
||||
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:customer: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 identifier confirmed and recorded (decision record or
|
||||
canon note); a test-subject token carries the correct `tenant` claim.
|
||||
|
||||
## Task: Provision bernd.worsch@binky-hedgehog.com as tenant-admin
|
||||
|
||||
```task
|
||||
id: KEY-WP-0004-T02
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
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:customer: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:customer: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
|
||||
|
||||
```task
|
||||
id: KEY-WP-0004-T03
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
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:customer: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:customer: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
|
||||
|
||||
```task
|
||||
id: KEY-WP-0004-T04
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
```task
|
||||
id: KEY-WP-0004-T05
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
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, 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.
|
||||
|
||||
## Task: automation@binky-hedgehog.com service identity (deferred)
|
||||
|
||||
```task
|
||||
id: KEY-WP-0004-T06
|
||||
status: todo
|
||||
priority: low
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
```task
|
||||
id: KEY-WP-0004-T07
|
||||
status: todo
|
||||
priority: low
|
||||
```
|
||||
|
||||
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 (qonto-assistant workload client) both resolve to `tenant:customer: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`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue