Bind platform OpenBao service identity to tenant zero
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 4s

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 cbe218b26a
commit f0d82908e9
6 changed files with 35 additions and 17 deletions

View file

@ -6,7 +6,7 @@ secrets-engine now implements the consumer half of KeyCape's accepted
the non-cryptographic contract before any future OpenBao login: the non-cryptographic contract before any future OpenBao login:
- subject `service:secrets-engine`, audience/client `secrets-engine-openbao`; - subject `service:secrets-engine`, audience/client `secrets-engine-openbao`;
- service principal in `tenant:coulomb`, role `secrets-engine`; - service principal in `tenant:platform` (platform infrastructure, tenant zero), role `secrets-engine`;
- exact `openbao:login` scope and KeyCape AAL1 client-secret assurance; - exact `openbao:login` scope and KeyCape AAL1 client-secret assurance;
- RS256 declaration, bounded issue/expiry timestamps, maximum 15-minute life, - RS256 declaration, bounded issue/expiry timestamps, maximum 15-minute life,
and renewal when no more than three minutes remain; and renewal when no more than three minutes remain;

View file

@ -1,3 +1,10 @@
> Superseded source finding, 2026-09-27: the operator confirmed that OpenBao
> and its infrastructure service identities belong to `tenant:platform` (tenant
> zero). Coulomb is a workload tenant. The former `service_auth.TENANT` value
> discussed below is historical; source preflight now requires platform and
> rejects Coulomb. Live migration remains SECRETS-WP-0008-T06. See the platform
> owner's `docs/platform-tenant-essentials-review.md` for the cross-repo review.
# Tenant alignment # Tenant alignment
Answer to the `GLAS-WP-0015` production-dependency handoff question, which asked Answer to the `GLAS-WP-0015` production-dependency handoff question, which asked

View file

@ -36,11 +36,9 @@ DIGEST_RE = re.compile(r"^sha256:[0-9a-f]{64}$")
#: the vendored replay fixtures in ``tests/test_decision_replay.py`` instead of #: the vendored replay fixtures in ``tests/test_decision_replay.py`` instead of
#: being left to a deployment to supply correctly. #: being left to a deployment to supply correctly.
#: #:
#: This is not the KeyCape JWT tenant. ``service_auth.TENANT`` is #: Operator clarification, 2026-09-27: the platform infrastructure identity
#: ``tenant:coulomb``, which is the exact value this package denies. Whether #: also belongs to tenant:platform. Keep audience-specific profile validation;
#: those name one tenant or two layers is an open owner question -- see #: matching tenant strings do not grant cross-audience or workload authority.
#: ``docs/tenant-alignment.md`` -- and is deliberately not resolved by reusing
#: one constant for both.
REQUEST_TENANT = "tenant:platform" REQUEST_TENANT = "tenant:platform"
SCHEMA_VERSION = "0.1" SCHEMA_VERSION = "0.1"

View file

@ -1,7 +1,7 @@
"""KeyCape service-JWT exchange shared by two separately validated profiles. """KeyCape service-JWT exchange shared by two separately validated profiles.
The OpenBao login profile and approval consumer profile have distinct clients, The OpenBao login profile and approval consumer profile have distinct clients,
audiences, tenants and scopes. Provider selection never falls back to another audiences and scopes; both belong to tenant:platform. Provider selection never falls back to another
identity. Token parsing is a claim preflight, not signature verification: the identity. Token parsing is a claim preflight, not signature verification: the
receiving OpenBao or approval-engine service verifies RS256 before accepting it. receiving OpenBao or approval-engine service verifies RS256 before accepting it.
""" """
@ -24,7 +24,7 @@ from secrets_engine.openbao import read_strict_token_file
CLIENT_ID = "secrets-engine-openbao" CLIENT_ID = "secrets-engine-openbao"
SUBJECT = "service:secrets-engine" SUBJECT = "service:secrets-engine"
PRINCIPAL_TYPE = "service" PRINCIPAL_TYPE = "service"
TENANT = "tenant:coulomb" TENANT = "tenant:platform"
ROLE = "secrets-engine" ROLE = "secrets-engine"
SCOPE = "openbao:login" SCOPE = "openbao:login"
MAX_TOKEN_SECONDS = 15 * 60 MAX_TOKEN_SECONDS = 15 * 60

View file

@ -30,7 +30,7 @@ def _jwt(**overrides):
"iat": now, "iat": now,
"exp": now + 900, "exp": now + 900,
"principal_type": "service", "principal_type": "service",
"tenant": "tenant:coulomb", "tenant": "tenant:platform",
"roles": ["secrets-engine"], "roles": ["secrets-engine"],
"groups": [], "groups": [],
"scope": "openbao:login", "scope": "openbao:login",
@ -68,6 +68,7 @@ def test_preflight_accepts_exact_service_contract_and_renewal_window():
({"iss": "https://attacker.test"}, "'iss'"), ({"iss": "https://attacker.test"}, "'iss'"),
({"sub": "service:operator"}, "'sub'"), ({"sub": "service:operator"}, "'sub'"),
({"aud": "different"}, "'aud'"), ({"aud": "different"}, "'aud'"),
({"tenant": "tenant:coulomb"}, "'tenant'"),
({"tenant": "tenant:other"}, "'tenant'"), ({"tenant": "tenant:other"}, "'tenant'"),
({"roles": ["admin"]}, "roles"), ({"roles": ["admin"]}, "roles"),
({"scope": "openbao:login admin"}, "scope"), ({"scope": "openbao:login admin"}, "scope"),

View file

@ -331,7 +331,7 @@ Acceptance:
```task ```task
id: SECRETS-WP-0008-T06 id: SECRETS-WP-0008-T06
status: wait status: wait
blocking_reason: "RPF-WP-0035-T02 still awaits exact service claims/tenant, credential custody and scoped attended JWT role provisioning with native login/negative/revocation proof. The historical env-auth acceptance is not service-JWT adoption." blocking_reason: "RPF-WP-0035-T02 awaits coordinated platform-tenant live registration, credential custody and scoped attended JWT role provisioning with native login/negative/revocation proof. The historical env-auth acceptance is not service-JWT adoption."
priority: medium priority: medium
state_hub_task_id: "d7bc8bdc-a0f8-5058-a640-374ef9859148" state_hub_task_id: "d7bc8bdc-a0f8-5058-a640-374ef9859148"
``` ```
@ -354,12 +354,13 @@ Designed: role/audience `secrets-engine-openbao`, subject
budget, login-only. KeyCape issuer `https://kc.coulomb.social` and its JWKS are budget, login-only. KeyCape issuer `https://kc.coulomb.social` and its JWKS are
now confirmed live, so the remaining blocker is this registration's issued now confirmed live, so the remaining blocker is this registration's issued
claims, consumer readiness, an approved source and attended apply authority. claims, consumer readiness, an approved source and attended apply authority.
**Open question for secrets-engine, not answered in the triage session:** the **Resolved by the operator, 2026-09-27:** OpenBao is platform infrastructure,
JWT design says `tenant:coulomb`, while the approval chain resolved to belonging to tenant zero, `tenant:platform`. Coulomb is a workload tenant;
`tenant:platform` (decision `5ed3fb35`) and approval-engine compares tenant by its DNS domain does not own the platform. The former matching Coulomb claims
exact string. Which tenant the OpenBao service identity carries is a design were incorrect. KeyCape registrations, platform JWT roles and this consumer's
decision for an owner session; platform will correct its design before the strict preflight are corrected together in source. Live registration/custody,
role exists once told. A service login grants no lane mutation authority. Companion §7 / statute §3.4: an coordinated deployment and native refusal/revocation proof remain T06.
A service login grants no lane mutation authority. Companion §7 / statute §3.4: an
agent holds no long-lived credential of its own. Authority is per task, agent holds no long-lived credential of its own. Authority is per task,
time-bounded, and attributable to the principal it acts for. time-bounded, and attributable to the principal it acts for.
@ -511,6 +512,17 @@ refuses nested/identity-bearing version pins and names the accepted text and
rulings on every run, including PASS. Declaration spellings are unchanged. rulings on every run, including PASS. Declaration spellings are unchanged.
T06 remains wait: railiance-platform's RPF-WP-0035-T02 still records an T06 remains wait: railiance-platform's RPF-WP-0035-T02 still records an
unprovisioned, login-only JWT role, pending exact service claims/tenant and unprovisioned, login-only JWT role, pending platform-tenant live registration and
custody/attended admission. The existing env-auth native receipt cannot prove custody/attended admission. The existing env-auth native receipt cannot prove
steady-state service JWT login. This is the only remaining task in this workplan. steady-state service JWT login. This is the only remaining task in this workplan.
### 2026-09-27 platform essentials follow-up
Operator tenant-zero decision `be5287cb-d458-47bc-9183-2a40dd7ae04b` corrects
OpenBao infrastructure identities to `tenant:platform`. Source changes are
coordinated in KeyCape, railiance-platform and Secrets Engine. The platform
owner records the bounded essentials review in
`docs/platform-tenant-essentials-review.md`. T06 remains wait for coordinated
live registration/custody, provisioning and native refusal/revocation evidence.
No new task or workplan was created. Warden's npm no-rotation hold remains;
factory records now consume the completed generic approval and companion returns.