Prepare tenant-zero OpenBao roles and review platform essentials
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e324-abce-7e51-bb2b-496f097afdb0
This commit is contained in:
parent
4f20e755c4
commit
5781d34b3b
10 changed files with 179 additions and 14 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
# Secrets-engine service JWT login
|
# Secrets-engine service JWT login
|
||||||
|
|
||||||
Status: proposed, not provisioned. Owner: railiance-platform, RPF-WP-0032.
|
Status: proposed, not provisioned. Owner: railiance-platform, RPF-WP-0035-T02 (design origin RPF-WP-0032).
|
||||||
Demand: State Hub message `38b47122-07eb-4a7f-a5df-13a38f50e110`.
|
Demand: State Hub message `38b47122-07eb-4a7f-a5df-13a38f50e110`.
|
||||||
|
|
||||||
## Contract and ownership
|
## Contract and ownership
|
||||||
|
|
@ -20,11 +20,11 @@ or the coding-agent mount to introduce this service.
|
||||||
|
|
||||||
| Setting | Proposed value / evidence required |
|
| Setting | Proposed value / evidence required |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Verification | RS256 only; exact HTTPS issuer and approved discovery/JWKS URL, both pending KeyCape owner confirmation |
|
| Verification | RS256 only; issuer `https://kc.coulomb.social`, JWKS `https://kc.coulomb.social/jwks`; public discovery rechecked 2026-09-27; live registration remains unverified |
|
||||||
| Role type / user claim | `jwt` / `sub` |
|
| Role type / user claim | `jwt` / `sub` |
|
||||||
| Audience | `secrets-engine-openbao` |
|
| Audience | `secrets-engine-openbao` |
|
||||||
| Subject | `service:secrets-engine` |
|
| Subject | `service:secrets-engine` |
|
||||||
| Bound claims, string matching | `principal_type=service`, `tenant=tenant:coulomb`, required `roles=secrets-engine`, `scope=openbao:login` |
|
| Bound claims, string matching | `principal_type=service`, `tenant=tenant:platform`, required `roles=secrets-engine`, `scope=openbao:login` |
|
||||||
| Token policy | `secrets-engine-login-self` only; no default policy |
|
| Token policy | `secrets-engine-login-self` only; no default policy |
|
||||||
| Token bounds | service token, TTL/max/explicit max `5m`, 8 uses, no periodic token; budget must include cleanup |
|
| Token bounds | service token, TTL/max/explicit max `5m`, 8 uses, no periodic token; budget must include cleanup |
|
||||||
| Logging | verbose OIDC logging disabled; no JWT claim dump or token/accessor in receipts |
|
| Logging | verbose OIDC logging disabled; no JWT claim dump or token/accessor in receipts |
|
||||||
|
|
@ -96,3 +96,27 @@ OpenBao's [JWT documentation](https://openbao.org/docs/auth/jwt/) describes
|
||||||
signature verification and claim binding; its [role API](https://openbao.org/docs/2.4.x/api/auth/jwt/)
|
signature verification and claim binding; its [role API](https://openbao.org/docs/2.4.x/api/auth/jwt/)
|
||||||
defines token TTL/use limits and the explicit maximum. These are mechanism
|
defines token TTL/use limits and the explicit maximum. These are mechanism
|
||||||
references, not evidence of this cluster's installed configuration.
|
references, not evidence of this cluster's installed configuration.
|
||||||
|
|
||||||
|
## Prepared source return — 2026-09-27
|
||||||
|
|
||||||
|
The exact proposed bundle is `openbao/auth/keycape-services-config.json`,
|
||||||
|
`openbao/auth/secrets-engine-jwt-role.json` and
|
||||||
|
`openbao/policies/secrets-engine-login-self.hcl`. These files are non-secret
|
||||||
|
inputs for the existing attended platform procedure, not an applied receipt.
|
||||||
|
The discovery document advertises `/token` and `client_credentials`.
|
||||||
|
|
||||||
|
The operator clarified that platform infrastructure belongs to tenant zero,
|
||||||
|
`tenant:platform`. Coulomb is a workload tenant; its DNS domain is not ownership.
|
||||||
|
The former `tenant:coulomb` service registration and consumer preflight were
|
||||||
|
consistent but incorrectly scoped. The corrected source uses `tenant:platform`
|
||||||
|
for both OpenBao infrastructure clients and the existing approval clients.
|
||||||
|
|
||||||
|
Before writing: survey mounts/roles, confirm exact live client registration and
|
||||||
|
protected client-side custody, review this bundle and obtain the scoped attended
|
||||||
|
window via `warden access openbao-platform-admin-login --exec -- <reviewed-command>`.
|
||||||
|
Do not execute a placeholder command. The reviewed child must install only this
|
||||||
|
isolated mount/config, self policy and role, compare effective policy metadata,
|
||||||
|
then perform the positive/negative/expiry/use-limit/revocation checks above.
|
||||||
|
Do not print login responses. Publish the consumer contract only after those
|
||||||
|
checks pass. A conflicting existing mount/role requires review, not overwrite.
|
||||||
|
No service-client secret is created, moved or requested by this source return.
|
||||||
|
|
|
||||||
43
docs/platform-tenant-essentials-review.md
Normal file
43
docs/platform-tenant-essentials-review.md
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
# Platform essentials tenant review — 2026-09-27
|
||||||
|
|
||||||
|
Operator requirement: `tenant:platform` is tenant zero for platform infrastructure.
|
||||||
|
`tenant:coulomb` is a workload/product tenant. The shared `coulomb.social` DNS
|
||||||
|
suffix does not establish tenant ownership. Provider ownership, caller identity,
|
||||||
|
resource tenant and enforcement capability are separate facts.
|
||||||
|
|
||||||
|
| Essential / boundary | Source reviewed | Result and action |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| OpenBao custody/provider | `tenancy.yaml`, `docs/tenancy-posture.md`, `openbao/auth/` | Platform-owned. Correct both infrastructure JWT roles to platform; retain exact audience/subject/scope and bounded policies. |
|
||||||
|
| Platform coding agent | KeyCape service registration; `coding-agent-jwt-role.json` | Incorrect Coulomb claim corrected in both source owners. Existing workload read policy remains explicit; changing identity tenant grants no additional data access. |
|
||||||
|
| Secrets Engine service login | KeyCape registration; consumer `service_auth.py`; proposed service role | Incorrect Coulomb claim corrected together to platform. Login-only self policy; no lane mutation privilege. |
|
||||||
|
| Approval / informed decision / policy checks | KeyCape registrations; Secrets Engine approval and authorization profiles | Already platform-bound. Keep exact tenant comparison, distinct audiences/scopes and human controls. |
|
||||||
|
| Audit senders | `docs/credential-lane-designs/factory-audit-senders-review.md`; Audit Core tenancy declaration | Factory senders already restricted to platform. Provider ownership does not relabel historical events or consumer tenants. |
|
||||||
|
| KeyCape human directory fallback | KeyCape `token.go`, tenant claim contract | Still legacy `tenant:coulomb` when directory tenant is missing. Do not change the default to platform: that would implicitly elevate unclassified users. Explicit platform registration/directory binding remains necessary. |
|
||||||
|
| Shared PostgreSQL / Forgejo database | `tenancy.yaml`, `docs/tenancy-posture.md`, rapp-postgres declarations | Platform provider ownership; consumers retain their databases and workload isolation. No tenant claim is implemented at the substrate by these declarations. |
|
||||||
|
| OpenBao package | rapp-openbao YAML/JSON source review | No runtime tenant claim found in package declarations; package ownership and the auth role bindings above must not be inferred from ingress DNS. Absence of a claim is not live verification. |
|
||||||
|
| Warden / Forgejo | Warden tenancy declaration; Forgejo YAML/JSON source review | Infrastructure belongs to platform. SSH, package and workload grants retain their explicit identities; do not replace Coulomb organization or KV path components with platform. |
|
||||||
|
|
||||||
|
This is a bounded source review of the existing credential-chain dependencies,
|
||||||
|
not a claim that every platform deployment has been audited. No live tenant
|
||||||
|
migration, token issuance, value read or workload relocation was performed.
|
||||||
|
The existing RPF-WP-0035-T02 owns the coordinated service-login return; existing
|
||||||
|
KEY-WP-0009 contract and SECRETS-WP-0008-T06 carry provider/consumer changes.
|
||||||
|
No new work item is opened.
|
||||||
|
|
||||||
|
## Deployment and acceptance
|
||||||
|
|
||||||
|
1. Inventory exact live KeyCape registrations and OpenBao mount/roles using
|
||||||
|
metadata-only, attended authority. Source files are not live-state receipts.
|
||||||
|
2. Compare issuer, audience, subject, tenant, policies and aliases. Preserve
|
||||||
|
workload grants; do not introduce a tenant alias or accept both tenants.
|
||||||
|
3. Coordinate issuance and verifier/consumer deployment. Old Coulomb-bound
|
||||||
|
platform JWTs must fail; new platform-bound JWTs must succeed. Rollback is
|
||||||
|
an explicit coordinated restoration, never a fallback to another identity.
|
||||||
|
4. Already-issued OpenBao tokens do not change tenant/policies when a JWT role
|
||||||
|
changes. Revoke affected tokens under owner custody and verify denial. Bound
|
||||||
|
the remaining JWT and token lifetimes; retain only non-secret results.
|
||||||
|
5. Prove wrong-tenant/audience/subject/scope refusal, exact effective policies,
|
||||||
|
expiry/use limits and self-revocation before publishing the consumer contract.
|
||||||
|
|
||||||
|
Tenant ownership does not raise the historical I/A/E/R/V posture scores. The
|
||||||
|
posture records describe demonstrated isolation/recovery, not the owner tenant.
|
||||||
|
|
@ -256,3 +256,12 @@ renumbered.
|
||||||
Six months, or on any of: a service moving placement level, a backup target
|
Six months, or on any of: a service moving placement level, a backup target
|
||||||
becoming available, or the framework reaching `accepted`. Next review due
|
becoming available, or the framework reaching `accepted`. Next review due
|
||||||
**2027-02-17**.
|
**2027-02-17**.
|
||||||
|
|
||||||
|
## Platform ownership clarification — 2026-09-27
|
||||||
|
|
||||||
|
All infrastructure providers in this declaration belong to `tenant:platform`
|
||||||
|
(tenant zero), including OpenBao, shared PostgreSQL and Forgejo's database.
|
||||||
|
Coulomb is a workload tenant; DNS under `coulomb.social` does not assign these
|
||||||
|
providers to it. Provider ownership is separate from the measured tenancy
|
||||||
|
posture axes and from each credential or database consumer's resource tenant.
|
||||||
|
See [the source review and migration requirements](platform-tenant-essentials-review.md).
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
"bound_claims": {
|
"bound_claims": {
|
||||||
"sub": "service:codex:railiance-platform",
|
"sub": "service:codex:railiance-platform",
|
||||||
"principal_type": "service",
|
"principal_type": "service",
|
||||||
"tenant": "tenant:coulomb",
|
"tenant": "tenant:platform",
|
||||||
"roles": "coding-agent"
|
"roles": "coding-agent"
|
||||||
},
|
},
|
||||||
"token_policies": [
|
"token_policies": [
|
||||||
|
|
|
||||||
7
openbao/auth/keycape-services-config.json
Normal file
7
openbao/auth/keycape-services-config.json
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"jwks_url": "https://kc.coulomb.social/jwks",
|
||||||
|
"bound_issuer": "https://kc.coulomb.social",
|
||||||
|
"jwt_supported_algs": [
|
||||||
|
"RS256"
|
||||||
|
]
|
||||||
|
}
|
||||||
25
openbao/auth/secrets-engine-jwt-role.json
Normal file
25
openbao/auth/secrets-engine-jwt-role.json
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"role_type": "jwt",
|
||||||
|
"user_claim": "sub",
|
||||||
|
"bound_audiences": [
|
||||||
|
"secrets-engine-openbao"
|
||||||
|
],
|
||||||
|
"bound_subject": "service:secrets-engine",
|
||||||
|
"bound_claims_type": "string",
|
||||||
|
"bound_claims": {
|
||||||
|
"principal_type": "service",
|
||||||
|
"tenant": "tenant:platform",
|
||||||
|
"roles": "secrets-engine",
|
||||||
|
"scope": "openbao:login"
|
||||||
|
},
|
||||||
|
"token_policies": [
|
||||||
|
"secrets-engine-login-self"
|
||||||
|
],
|
||||||
|
"token_no_default_policy": true,
|
||||||
|
"token_type": "service",
|
||||||
|
"token_ttl": "5m",
|
||||||
|
"token_max_ttl": "5m",
|
||||||
|
"token_explicit_max_ttl": "5m",
|
||||||
|
"token_num_uses": 8,
|
||||||
|
"verbose_oidc_logging": false
|
||||||
|
}
|
||||||
10
openbao/policies/secrets-engine-login-self.hcl
Normal file
10
openbao/policies/secrets-engine-login-self.hcl
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
# RPF-WP-0035-T02: proposed login-only service policy; not a lane applier.
|
||||||
|
path "auth/token/lookup-self" {
|
||||||
|
capabilities = ["read"]
|
||||||
|
}
|
||||||
|
path "sys/capabilities-self" {
|
||||||
|
capabilities = ["update"]
|
||||||
|
}
|
||||||
|
path "auth/token/revoke-self" {
|
||||||
|
capabilities = ["update"]
|
||||||
|
}
|
||||||
|
|
@ -247,7 +247,7 @@ class CredentialChangeTests(unittest.TestCase):
|
||||||
{
|
{
|
||||||
"sub": "service:codex:railiance-platform",
|
"sub": "service:codex:railiance-platform",
|
||||||
"principal_type": "service",
|
"principal_type": "service",
|
||||||
"tenant": "tenant:coulomb",
|
"tenant": "tenant:platform",
|
||||||
"roles": "coding-agent",
|
"roles": "coding-agent",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
30
tests/test_secrets_engine_jwt_contract.py
Normal file
30
tests/test_secrets_engine_jwt_contract.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
"""Source safety bounds; live JWT verification remains attended acceptance."""
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
class ServiceJWTContract(unittest.TestCase):
|
||||||
|
def test_platform_identity_is_exact_and_cannot_be_an_applier(self):
|
||||||
|
role = json.loads((ROOT / "openbao/auth/secrets-engine-jwt-role.json").read_text())
|
||||||
|
self.assertEqual(role["bound_audiences"], ["secrets-engine-openbao"])
|
||||||
|
self.assertEqual(role["bound_subject"], "service:secrets-engine")
|
||||||
|
self.assertEqual(role["bound_claims"], dict(principal_type="service", tenant="tenant:platform", roles="secrets-engine", scope="openbao:login"))
|
||||||
|
self.assertEqual(role["bound_claims_type"], "string")
|
||||||
|
self.assertEqual(role["token_policies"], ["secrets-engine-login-self"])
|
||||||
|
self.assertTrue(role["token_no_default_policy"])
|
||||||
|
self.assertFalse(role["verbose_oidc_logging"])
|
||||||
|
self.assertEqual(role["token_type"], "service")
|
||||||
|
self.assertEqual(role["token_num_uses"], 8)
|
||||||
|
for key in ("token_ttl", "token_max_ttl", "token_explicit_max_ttl"):
|
||||||
|
self.assertEqual(role[key], "5m")
|
||||||
|
self.assertNotIn("token_period", role)
|
||||||
|
|
||||||
|
def test_only_self_endpoints_and_pinned_signature_verifier(self):
|
||||||
|
policy = (ROOT / "openbao/policies/secrets-engine-login-self.hcl").read_text()
|
||||||
|
grants = re.findall(r'path "([^"]+)"\s*{\s*capabilities = \["([^"]+)"\]', policy)
|
||||||
|
self.assertEqual(grants, [("auth/token/lookup-self", "read"), ("sys/capabilities-self", "update"), ("auth/token/revoke-self", "update")])
|
||||||
|
self.assertNotIn("*", policy)
|
||||||
|
config = json.loads((ROOT / "openbao/auth/keycape-services-config.json").read_text())
|
||||||
|
self.assertEqual(config, dict(jwks_url="https://kc.coulomb.social/jwks", bound_issuer="https://kc.coulomb.social", jwt_supported_algs=["RS256"]))
|
||||||
|
|
@ -8,7 +8,7 @@ status: blocked
|
||||||
flavor: implementation
|
flavor: implementation
|
||||||
owner: codex
|
owner: codex
|
||||||
created: "2026-09-05"
|
created: "2026-09-05"
|
||||||
updated: "2026-09-15"
|
updated: "2026-09-27"
|
||||||
related:
|
related:
|
||||||
- RPF-WP-0032
|
- RPF-WP-0032
|
||||||
- RPF-WP-0033
|
- RPF-WP-0033
|
||||||
|
|
@ -56,8 +56,9 @@ and a metadata-only custody receipt. KeyCape owns issuer/JWKS and service
|
||||||
registration (KEY-WP-0009); secrets-engine owns service authentication and
|
registration (KEY-WP-0009); secrets-engine owns service authentication and
|
||||||
authority consumption (SECRETS-WP-0008-T06, SECRETS-WP-0007-T04).
|
authority consumption (SECRETS-WP-0008-T06, SECRETS-WP-0007-T04).
|
||||||
|
|
||||||
**Unblock:** confirmed HTTPS issuer/JWKS, exact claims and audience, consumer
|
**Unblock:** live registration and protected client custody, reviewed exact source
|
||||||
readiness, approved source and attended apply authority. A service login does
|
and attended apply authority. Issuer/JWKS and consumer source claims now agree;
|
||||||
|
see the 2026-09-27 return below. A service login does
|
||||||
not grant lane mutation authority. Do not build another identity provider or
|
not grant lane mutation authority. Do not build another identity provider or
|
||||||
lifecycle engine here.
|
lifecycle engine here.
|
||||||
|
|
||||||
|
|
@ -276,15 +277,16 @@ governed lane is the live consumer. Do not wrap `secret/coulomb/whynot-design/np
|
||||||
in a CCR. Value remains unread. Platform will ask secrets-engine which path
|
in a CCR. Value remains unread. Platform will ask secrets-engine which path
|
||||||
publish actually reads before any attended destroy.
|
publish actually reads before any attended destroy.
|
||||||
|
|
||||||
**Unblock:** secrets-engine confirms which location their publish actually reads
|
**Unblock:** admit the governed exact-path AppRole policy and coordinated catalog
|
||||||
and whether the two hold the same value; the owner of the legacy path is
|
path/field migration under SECRETS-WP-0006-T06; prove native delivery from the
|
||||||
identified; and a metadata-or-field-name read of the legacy path is admitted so
|
governed lane before the attended legacy destroy. secrets-engine confirmed the
|
||||||
the duplicate can be characterised without reading its value.
|
legacy source path on 2026-09-21 (message `355424d4-17ab-435e-9e1d-6921775cb4a2`).
|
||||||
|
No comparison of values, fingerprints, lengths or shapes is needed or authorized.
|
||||||
|
|
||||||
**Done when:** the legacy path's provenance and consumer are established, the
|
**Done when:** the legacy path's provenance and consumer are established, the
|
||||||
governed lane is confirmed as the one in use or the consumer is moved to it as a
|
governed lane is confirmed as the one in use or the consumer is moved to it as a
|
||||||
reviewed lane change, the duplicate is destroyed or brought under a CCR with an
|
reviewed lane change, the duplicate is destroyed under the September 15 operator decision and the
|
||||||
owner, and the disposition is recorded. If the value proves to be live and
|
disposition is recorded. Do not bring the legacy duplicate under a CCR. If the value proves to be live and
|
||||||
ungoverned, treat it as an exposure with the same custody rules as RPF-WP-0027:
|
ungoverned, treat it as an exposure with the same custody rules as RPF-WP-0027:
|
||||||
never record the value, fingerprint, length or shape.
|
never record the value, fingerprint, length or shape.
|
||||||
|
|
||||||
|
|
@ -679,3 +681,18 @@ verify and exec using scoped attended authority, and capture native denial,
|
||||||
revocation, workload health and key-check evidence. No OpenRouter credential has
|
revocation, workload health and key-check evidence. No OpenRouter credential has
|
||||||
been read and no inference or spend was performed. T03 remains waiting; this
|
been read and no inference or spend was performed. T03 remains waiting; this
|
||||||
entry supersedes earlier statements that requester or group admission is missing.
|
entry supersedes earlier statements that requester or group admission is missing.
|
||||||
|
|
||||||
|
### 2026-09-27 T02/T07 source follow-up
|
||||||
|
|
||||||
|
T02 now has the exact proposed RS256 configuration, bounded JWT role and
|
||||||
|
self-only policy in `openbao/`. Operator correction: platform infrastructure
|
||||||
|
belongs to `tenant:platform`; KeyCape registration and consumer preflight are
|
||||||
|
corrected together. Existing live registrations must be migrated and verified.
|
||||||
|
Public discovery confirms issuer/JWKS/token endpoint. Registration/custody,
|
||||||
|
attended provisioning and live rejection/cleanup evidence remain required;
|
||||||
|
T02 stays wait. No service credential or backend entitlement was issued.
|
||||||
|
|
||||||
|
T07 consumed the confirmed legacy consumer return. The stale value-comparison
|
||||||
|
ask is removed. WARDEN-WP-0037-T03's no-rotation hold stays in force until the
|
||||||
|
governed native migration is evidenced. Legacy destruction follows migration;
|
||||||
|
neither source reconciliation nor the historical pilot is that evidence.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue