64 lines
3.4 KiB
Markdown
64 lines
3.4 KiB
Markdown
|
|
# Tenant claim contract
|
||
|
|
|
||
|
|
Answers the tenant-alignment question in glas-harness message
|
||
|
|
`356f6977-d361-4e3b-83ab-b2c7f4759286` (GLAS-WP-0015). It states what KeyCape
|
||
|
|
owns and emits; it does not create a mapping between tenant vocabularies.
|
||
|
|
|
||
|
|
## What KeyCape emits
|
||
|
|
|
||
|
|
The `tenant` claim is bound at registration or directory-resolution time and is
|
||
|
|
never influenced by request parameters.
|
||
|
|
|
||
|
|
| Principal | Source of `tenant` | Value in the reviewed registrations |
|
||
|
|
| --- | --- | --- |
|
||
|
|
| Service (`client_credentials`) | The client's `tenant` field. Required by config validation — a `client_credentials` client without `serviceSubject` and `tenant` fails startup validation. | `tenant:coulomb` for all four clients in `config/service-clients.example.yaml`, including `secrets-engine-approval` and `approval-engine-operator`. |
|
||
|
|
| Human (`authorization_code`) | The directory user's tenant, falling back to the platform default when unset. | Directory value, else `tenant:coulomb`. |
|
||
|
|
|
||
|
|
`tenant`, `tenant_hint`, `audience` and `resource` request parameters cannot
|
||
|
|
change the claim. `tenant_hint` on `/authorize` reaches registration/enrollment
|
||
|
|
handoffs only; it is not a claim input.
|
||
|
|
|
||
|
|
## The three values in the request
|
||
|
|
|
||
|
|
- **JWT tenant** — `tenant:coulomb`. Owned by KeyCape, emitted verbatim from the
|
||
|
|
registration above. This is the only one of the three KeyCape owns.
|
||
|
|
- **Approval store tenant** — `platform`. Owned by approval-engine.
|
||
|
|
- **Policy tenant / CheckRequest tenant** — `tenant:platform`. Owned by flex-auth.
|
||
|
|
|
||
|
|
KeyCape performs **no** normalization, prefix-stripping or aliasing. A resource
|
||
|
|
server comparing `tenant` must use exact string comparison, so as things stand a
|
||
|
|
token issued to `secrets-engine-approval` (`tenant:coulomb`) does not match an
|
||
|
|
approval store tenant `platform` or a policy tenant `tenant:platform`.
|
||
|
|
|
||
|
|
## What is not decided here
|
||
|
|
|
||
|
|
Whether these three identify the same tenant across layers is not a KeyCape
|
||
|
|
decision, and spelling similarity is not a mapping. Two admissible resolutions
|
||
|
|
exist, both owned outside this repository:
|
||
|
|
|
||
|
|
1. The consuming owners accept `tenant:coulomb` as the JWT tenant and record the
|
||
|
|
layer mapping in their own contract; KeyCape changes nothing.
|
||
|
|
2. The owners decide the approval clients belong to a different tenant, in which
|
||
|
|
case KeyCape changes the `tenant` field on those two registrations only, under
|
||
|
|
an explicit decision reference, and re-issues.
|
||
|
|
|
||
|
|
KeyCape will not change the `tenant` value on a live registration without such a
|
||
|
|
reference. No unilateral change to live clients or policy subjects was made.
|
||
|
|
|
||
|
|
## Evidence
|
||
|
|
|
||
|
|
`src/internal/server/oidc/tenant_test.go`:
|
||
|
|
|
||
|
|
- `TestServiceTenantIsBoundToRegistrationAndIgnoresRequestParameters` — a request
|
||
|
|
supplying `tenant=tenant:platform` and `tenant_hint=platform` still yields the
|
||
|
|
registered `tenant`, signature-verified against `/jwks`.
|
||
|
|
- `TestServiceTenantsAreDistinctPerRegistration` — two registrations with
|
||
|
|
different tenants yield their own values and never each other's; this is the
|
||
|
|
wrong-tenant denial basis for an exact-comparison resource server.
|
||
|
|
- `TestHumanTenantClaimUsesDirectoryValueThenPlatformDefault` — human tokens carry
|
||
|
|
the directory tenant, defaulting to `tenant:coulomb` rather than an empty claim.
|
||
|
|
|
||
|
|
These are local issuance proofs. They are not live-rollout evidence; see
|
||
|
|
`docs/approval-engine-auth-contract.md` and KEY-WP-0013-T02 for the deployment
|
||
|
|
boundary. No token or secret values appear in this document or in test output.
|