diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index 2eaf15a..73f0e3e 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -11,7 +11,7 @@ | workplan | KEY-WP-0001 | done | — | workplans/KEY-WP-0001-keycape-implementation.md | | workplan | KEY-WP-0002 | done | — | workplans/KEY-WP-0002-container-image-gitea.md | | workplan | KEY-WP-0003 | finished | — | workplans/KEY-WP-0003-bootstrap-console-oidc-mfa-login.md | -| workplan | KEY-WP-0004 | ready | — | workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md | +| workplan | KEY-WP-0004 | active | — | workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md | | workplan | KEY-WP-0005 | finished | — | workplans/KEY-WP-0005-iam-profile-core-claims.md | | task | KEY-WP-0001-T01 | done | — | workplans/KEY-WP-0001-keycape-implementation.md | | task | KEY-WP-0001-T02 | done | — | workplans/KEY-WP-0001-keycape-implementation.md | @@ -49,9 +49,9 @@ | task | KEY-WP-0003-T05 | done | — | workplans/KEY-WP-0003-bootstrap-console-oidc-mfa-login.md | | task | KEY-WP-0004-T01 | todo | — | workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md | | task | KEY-WP-0004-T02 | todo | — | workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md | -| task | KEY-WP-0004-T03 | todo | — | workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md | -| task | KEY-WP-0004-T04 | todo | — | workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md | -| task | KEY-WP-0004-T05 | todo | — | workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md | +| task | KEY-WP-0004-T03 | progress | — | workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md | +| task | KEY-WP-0004-T04 | progress | — | workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md | +| task | KEY-WP-0004-T05 | progress | — | workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md | | task | KEY-WP-0004-T06 | todo | — | workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md | | task | KEY-WP-0004-T07 | todo | — | workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md | | task | KEY-WP-0005-T01 | done | — | workplans/KEY-WP-0005-iam-profile-core-claims.md | diff --git a/docs/qonto-runtime-identity-contract.md b/docs/qonto-runtime-identity-contract.md new file mode 100644 index 0000000..714a84c --- /dev/null +++ b/docs/qonto-runtime-identity-contract.md @@ -0,0 +1,59 @@ +# Qonto Runtime Identity Contract + +Date: 2026-07-26 +Status: Provisioning-ready; tenant canon decision and first issue remain open + +## Stable Names + +- runtime package/principal: `rapp-qonto` +- service account: `rapp-qonto` +- non-interactive caller client: `rapp-qonto-client` +- OpenBao runtime role: `rapp-qonto` +- existing bank credential reference: `tenants/binky/qonto-api` +- tenant claim: `tenant:friendly:binky`, subject to the open NetKingdom canon + alignment already recorded in `KEY-WP-0004` + +Any identity or role named `qonto-assistant` is a migration bridge with an +owner and expiry, not the steady-state contract. + +## Least-Privilege Contract + +The runtime client: + +- uses a non-interactive workload grant +- receives only the Binky tenant claim and the minimum Qonto runtime scopes +- receives no platform-root, other-tenant, or tenant-admin authority +- uses short-lived tokens +- is independently revocable + +The workload role may resolve only the Qonto runtime secret references required +by the package. Positive access and unrelated-role denial must both be tested. + +## Automation And Custody + +Credential planning begins with `warden plan`. + +The 2026-07-26 plan result is: + +- Forgejo and deployment-key use can be autonomous through sanctioned + `warden access --exec`, `--out`, or `--wrap` transports. +- First-time provisioning of a new OpenBao value remains one explicit founder + authority act through `warden desk`; agents must not replace it with a file + drop or captured stdout. +- The existing Qonto bank credential lane is resolvable but high risk and must + never be streamed to an agent. + +After the first authority act, issuance tests, negative access, revocation, +posture conformance, route discovery, and evidence reconciliation should be +agent-executable and then scheduled where stable. + +## Required Non-Secret Evidence + +- client id, issuer, audiences, scopes, token TTL, and tenant claim +- workload role and secret-reference path names +- positive token exchange without token disclosure +- wrong-tenant and excessive-scope denial +- positive/negative OpenBao capability checks +- revocation result +- ops-warden route and conformance result +- migration-bridge expiry, if used diff --git a/workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md b/workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md index db0e1aa..0776d1f 100644 --- a/workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md +++ b/workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md @@ -1,18 +1,18 @@ --- id: KEY-WP-0004 type: workplan -title: "Binky Hedgehog GmbH as first NetKingdom tenant + qonto-assistant workload identity" +title: "Binky Hedgehog GmbH as first NetKingdom tenant + qonto runtime workload identity" domain: infotech repo: key-cape -status: ready +status: active owner: codex topic_slug: netkingdom created: "2026-07-23" -updated: "2026-07-23" +updated: "2026-07-26" state_hub_workstream_id: "ad6fa711-ba5b-4e7d-86e3-641f9acaf853" --- -# Binky Hedgehog GmbH as first NetKingdom tenant + qonto-assistant workload identity +# 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 @@ -32,13 +32,15 @@ profile's `client_credentials`/workload-identity grant for service accounts **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). +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`. -**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=)` -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. +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 @@ -129,11 +131,11 @@ 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 +## Task: Register a workload-identity OIDC client for the qonto runtime ```task id: KEY-WP-0004-T03 -status: todo +status: progress priority: high state_hub_task_id: "fbe9d2e0-7532-4403-8e12-947aa8fd0da7" ``` @@ -141,9 +143,12 @@ 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. +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 @@ -151,35 +156,46 @@ 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. +`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: todo +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 — 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. +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: `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. +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: todo +status: progress priority: high state_hub_task_id: "a91326a6-f498-4569-a56b-95a49fe5794d" ``` @@ -190,20 +206,28 @@ 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. +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 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). +(`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 @@ -215,7 +239,7 @@ 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. +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. @@ -240,9 +264,9 @@ 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 (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 +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`.