Define Qonto runtime identity contract

This commit is contained in:
tegwick 2026-07-26 13:34:56 +02:00
parent 739b1f5c72
commit 86e6c083f7
3 changed files with 125 additions and 42 deletions

View file

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

View file

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

View file

@ -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=<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.
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, M0M3 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, 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.
## 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 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
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`.