Correct platform infrastructure client tenant bindings

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e324-abce-7e51-bb2b-496f097afdb0
This commit is contained in:
tegwick 2026-09-27 16:43:31 +02:00
parent 3b0446e0ef
commit 717a97408a
7 changed files with 47 additions and 16 deletions

View file

@ -9,7 +9,7 @@ clients:
clientType: "confidential"
secretRef: "env:KEYCAPE_CODEX_RAILIANCE_PLATFORM_CLIENT_SECRET"
serviceSubject: "service:codex:railiance-platform"
tenant: "tenant:coulomb"
tenant: "tenant:platform"
roles: ["coding-agent"]
tokenLifetime: "15m"
@ -20,7 +20,7 @@ clients:
clientType: "confidential"
secretRef: "env:KEYCAPE_SECRETS_ENGINE_OPENBAO_CLIENT_SECRET"
serviceSubject: "service:secrets-engine"
tenant: "tenant:coulomb"
tenant: "tenant:platform"
roles: ["secrets-engine"]
tokenLifetime: "15m"

View file

@ -84,3 +84,22 @@ break-glass providers and require their own authorization and evidence.
Verification must inspect metadata and capabilities without reading a secret
value. A coding-agent check must prove the `agent-high-risk-boundary` deny wins
against any otherwise readable workload policy.
## Consumer/platform reconciliation — 2026-09-27
The operator clarified that platform infrastructure belongs to tenant zero,
**`tenant:platform`**, including OpenBao and its platform service identities.
Coulomb is a workload on the platform; `coulomb.social` is currently shared DNS,
not a tenant assignment. The former matching `tenant:coulomb` declarations were
wrong. `codex-railiance-platform` and `secrets-engine-openbao` now declare
`tenant:platform`, coordinated with the platform role and consumer preflight.
This source correction does not migrate live registrations or existing tokens.
Public discovery at `https://kc.coulomb.social/.well-known/openid-configuration`
was rechecked: issuer `https://kc.coulomb.social`, JWKS `/jwks`, token endpoint
`/token`, with `client_credentials` advertised. This establishes public endpoint
metadata only, not that this confidential client is registered or provisioned.
Platform's RPF-WP-0035-T02 now carries the exact proposed login-only role/config/
policy. The remaining joint acceptance is protected client custody and actual
registration, attended role provisioning, native signature/claim refusals and
OpenBao self-revocation. KEY-WP-0009's provider-contract completion is unchanged.

View file

@ -18,8 +18,8 @@ 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. | In `config/service-clients.example.yaml`: `tenant:platform` for `secrets-engine-approval` and `approval-engine-operator`; `tenant:coulomb` for `codex-railiance-platform` and `secrets-engine-openbao`. |
| Human (`authorization_code`) | The directory user's tenant, falling back to the platform default when unset. | Directory value, else `tenant:coulomb`. |
| Service (`client_credentials`) | The client's `tenant` field. Required by config validation — a `client_credentials` client without `serviceSubject` and `tenant` fails startup validation. | In `config/service-clients.example.yaml`: `tenant:platform` for the platform approval clients, `codex-railiance-platform` and `secrets-engine-openbao` (operator correction, 2026-09-27). |
| Human (`authorization_code`) | The directory user's tenant, falling back to the legacy workload 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
@ -47,7 +47,9 @@ The decision changed the `tenant` field on exactly two registrations,
entries in `docs/approval-engine-provisioning-request.yaml`. Deliberately
unchanged:
- `codex-railiance-platform` and `secrets-engine-openbao` keep `tenant:coulomb`.
- Historical exception superseded 2026-09-27: `codex-railiance-platform` and
`secrets-engine-openbao` belong to `tenant:platform`; see the OpenBao contract.
Apply the issuer/role/consumer changes in a coordinated deployment window.
- Human directory resolution keeps its `tenant:coulomb` default.
- No cross-tenant grant is implied: a `tenant:platform` token conveys no reach
into `tenant:coulomb` resources, and audiences, scopes, subjects, roles,

View file

@ -57,8 +57,8 @@ func TestServiceRegistrationTenantsAreExactPerDecision(t *testing.T) {
want := map[string]string{
"secrets-engine-approval": "tenant:platform",
"approval-engine-operator": "tenant:platform",
"codex-railiance-platform": "tenant:coulomb",
"secrets-engine-openbao": "tenant:coulomb",
"codex-railiance-platform": "tenant:platform",
"secrets-engine-openbao": "tenant:platform",
// The only browser client here, and the only registration-supplied
// human tenant. Reviewed and added deliberately: this guard exists so a
// new client carrying a tenant cannot arrive unnoticed, and it did its

View file

@ -393,7 +393,7 @@ func TestServiceClientExampleContracts(t *testing.T) {
codingAgent := cfg.Clients[0]
if codingAgent.ClientID != "codex-railiance-platform" ||
codingAgent.ServiceSubject != "service:codex:railiance-platform" ||
codingAgent.Tenant != "tenant:coulomb" ||
codingAgent.Tenant != "tenant:platform" ||
codingAgent.TokenLifetime != "15m" {
t.Fatalf("coding-agent contract drifted: %+v", codingAgent)
}

View file

@ -118,7 +118,7 @@ func TestApprovalClientIssuesExactPlatformTenantAndRejectsAliases(t *testing.T)
GrantTypes: []string{"client_credentials"},
ClientType: "confidential",
ClientSecret: "approval-test-secret",
ServiceSubject: "service:secrets-engine",
ServiceSubject: "service:coulomb-workload-test",
Tenant: "tenant:platform",
Roles: []string{"secrets-engine"},
}
@ -147,22 +147,22 @@ func TestApprovalClientIssuesExactPlatformTenantAndRejectsAliases(t *testing.T)
}
}
// The aligned decision grants no cross-tenant reach: the unrelated OpenBao
// login client keeps tenant:coulomb.
// Platform ownership does not elevate workload clients. Request parameters
// cannot change a workload registration's tenant.
func TestUnrelatedServiceClientKeepsCoulombTenant(t *testing.T) {
h := serviceTokenHandler(t)
h.ClientConfig["secrets-engine-openbao"] = &domain.Client{
ClientID: "secrets-engine-openbao",
h.ClientConfig["coulomb-workload-test"] = &domain.Client{
ClientID: "coulomb-workload-test",
AllowedScopes: []string{"openbao:login"},
GrantTypes: []string{"client_credentials"},
ClientType: "confidential",
ClientSecret: "openbao-test-secret",
ServiceSubject: "service:secrets-engine",
ServiceSubject: "service:coulomb-workload-test",
Tenant: "tenant:coulomb",
Roles: []string{"secrets-engine"},
}
req := tokenRequest(url.Values{"grant_type": {"client_credentials"}, "scope": {"openbao:login"}, "tenant": {"tenant:platform"}})
req.SetBasicAuth("secrets-engine-openbao", "openbao-test-secret")
req.SetBasicAuth("coulomb-workload-test", "openbao-test-secret")
w := httptest.NewRecorder()
h.ServeHTTP(w, req)
if w.Code != http.StatusOK {

View file

@ -8,7 +8,7 @@ status: finished
owner: codex
topic_slug: netkingdom
created: "2026-08-23"
updated: "2026-09-08"
updated: "2026-09-27"
depends_on:
- NK-WP-0030
- KEY-WP-0006
@ -126,3 +126,13 @@ disablement and the claim set; secret custody, OpenBao roles/policies and token
enforcement, privacyIDEA factor and token lifecycle, resource authorization and
deployment remain with their named owners. C2a is not claimed. This closes the
notification gap; it is still not evidence of live deployment or provider cutover.
### 2026-09-27 operator tenant-zero correction
OpenBao infrastructure identities belong to `tenant:platform`, not Coulomb.
Corrected both static infrastructure registrations, matching source tests and
the tenant/OpenBao contracts. Consumer preflight and platform role sources are
updated together; no live registration or token migration is claimed. The
provider contract remains complete; RPF-WP-0035-T02 and SECRETS-WP-0008-T06
retain coordinated custody/deployment and native rejection/revocation proof.
Human fallback and workload tenant grants are not elevated to platform.