169 lines
10 KiB
Markdown
169 lines
10 KiB
Markdown
|
|
# MASON-WP-0009-T05: founder-run native capability proof
|
|||
|
|
|
|||
|
|
Preparation only. No credential was read, native session started, TokenRequest
|
|||
|
|
issued, policy widened, KV GET performed, or route activated during preparation.
|
|||
|
|
The existing T05 task stays in progress. Formal ops-mason owner source review,
|
|||
|
|
founder attendance approval for the exact staged digest, and live native receipts
|
|||
|
|
remain necessary. An `--approval-reference` argument records the founder's prior
|
|||
|
|
disposition; it cannot approve itself or establish runtime isolation.
|
|||
|
|
|
|||
|
|
## Exact reuse and authority
|
|||
|
|
|
|||
|
|
The existing verifier `scripts/verify-fluid-telegram-lane.sh` demonstrates attended
|
|||
|
|
OIDC and value-free capabilities, but accepts every failed login as a nonmember
|
|||
|
|
refusal. It is not reused as proof. secrets-engine's
|
|||
|
|
`OpenBaoOidcClientSecretSource` demonstrates `bao login -no-store -format=json`,
|
|||
|
|
but its next operation reads CLIENT_SECRET, so that provider is not invoked here.
|
|||
|
|
Existing `scripts/bao-session.sh grant MASON-WP-0009-T05` provides query authority:
|
|||
|
|
45m `ops-mason-survey`, founder minting, explicit data denies, no policy/role/token
|
|||
|
|
write. The grant may also carry `default`; all other token/identity policies are
|
|||
|
|
refused. No new policy or credential owner is proposed.
|
|||
|
|
|
|||
|
|
Source inspection found neither CCR-0033's ESO reader nor CCR-0034's operator
|
|||
|
|
reader grants `sys/capabilities-self` (both omit default). Calling capabilities
|
|||
|
|
under their own tokens would prove endpoint denial, not the required path matrix.
|
|||
|
|
The verifier uses the survey grant's existing `sys/capabilities` to query the
|
|||
|
|
native lane token in memory. The lane token never enters argv, environment,
|
|||
|
|
receipts or a token helper. All HTTP calls use a fixed loopback endpoint, reject
|
|||
|
|
redirects/proxies and allow only login, self lookup, capability query and self
|
|||
|
|
revocation endpoints. No secret or metadata GET exists in the HTTP interface.
|
|||
|
|
|
|||
|
|
Credential routing was read first: `WARDEN_MEMORY=0 warden route show
|
|||
|
|
openbao-structure-survey --json`. That entry routes to ops-mason and is not a
|
|||
|
|
credential vending surface. The initial default route lookup printed routing
|
|||
|
|
metadata but failed to append its memory event outside this sandbox; no escalation
|
|||
|
|
was requested. There is no active operator route in current ops-warden source;
|
|||
|
|
the previously reported draft proposal must be accepted there separately.
|
|||
|
|
|
|||
|
|
## Concrete attended proposal
|
|||
|
|
|
|||
|
|
Proposal ID: `MASON-WP-0009-T05-native-capability-proof-20261011`.
|
|||
|
|
Target: existing OpenBao on the railiance01 loopback tunnel and, for ESO only,
|
|||
|
|
railiance01's `external-secrets/external-secrets` ServiceAccount TokenRequest.
|
|||
|
|
Expected result: two exact native read-only matrices, confirmed lane/query
|
|||
|
|
self-revokes, and a separately accepted nonmember refusal. Estimated software
|
|||
|
|
cost EUR 0; bounded founder browser/session time around 10–20 minutes. Risk:
|
|||
|
|
short-lived read-capable session tokens exist in founder process memory, and ESO
|
|||
|
|
TokenRequest briefly mints a 10m JWT for the existing ServiceAccount. No secret
|
|||
|
|
value is requested. No policy or deployment changes occur. Actual runtime
|
|||
|
|
isolation remains unverified; exact source review and founder attendance are
|
|||
|
|
procedural gates, not an autopilot grant.
|
|||
|
|
|
|||
|
|
After ops-mason accepts the source and the supervisor records the exact digest
|
|||
|
|
and scoped founder go, the founder runs from their terminal. For each mode,
|
|||
|
|
obtain a fresh existing survey grant through the established session helper.
|
|||
|
|
Do not hand an agent an operator token or inspect either session file in chat.
|
|||
|
|
Use a new output path each time and a private browser session for the chosen human.
|
|||
|
|
The verifier requires TTY attendance, rejects ambient BAO_TOKEN/VAULT_TOKEN and
|
|||
|
|
namespaces, and refuses a source digest different from the reviewed digest.
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python3 scripts/verify-keycape-client-custody.py operator \
|
|||
|
|
--attended --approval-reference '<recorded founder disposition>' \
|
|||
|
|
--approved-source-sha256 '<reviewed script digest>' \
|
|||
|
|
--survey-token-fd 3 --receipt '<new absolute 0600 receipt path>' \
|
|||
|
|
3< "$HOME/.claude-bao-token"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Repeat with `eso` and then `nonmember`, fresh grant and receipt for each. Opening
|
|||
|
|
the existing grant FD is performed only in the founder terminal. The verifier
|
|||
|
|
closes it and self-revokes the query token. Existing `bao-session.sh revoke` is
|
|||
|
|
then used by the founder to remove the stale grant file; its printed success is
|
|||
|
|
not accepted as revocation evidence because that helper suppresses revoke errors.
|
|||
|
|
The verifier's native revoke receipt is the relevant evidence.
|
|||
|
|
|
|||
|
|
For ESO the runner first captures node metadata via fixed `ssh -oBatchMode=yes
|
|||
|
|
railiance01 'kubectl get nodes -o json'` and refuses any estate other than one node
|
|||
|
|
with address `92.205.62.239`. It then captures only the exact audience `openbao`,
|
|||
|
|
10m ServiceAccount TokenRequest JWT in memory and logs in at
|
|||
|
|
`auth/kubernetes/login` as `external-secrets-keycape-secrets-engine-openbao`.
|
|||
|
|
No Secret object, pod or controller token is read. The independently minted lane
|
|||
|
|
token is revoked; the running ESO controller's token is never touched. If the
|
|||
|
|
node metadata does not expose the documented IP, stop for platform owner source
|
|||
|
|
review of the estate pin; do not loosen the check at runtime.
|
|||
|
|
|
|||
|
|
## Receipt acceptance and remaining proof gates
|
|||
|
|
|
|||
|
|
Schema `mason-client-custody-native/v1` includes exact script digest, proposal
|
|||
|
|
reference, mode, timestamp, accessor SHA256, matrix and cleanup booleans. Files
|
|||
|
|
are reserved with O_EXCL/O_NOFOLLOW and mode 0600. Raw CLI/HTTP errors and auth
|
|||
|
|
responses are never copied into receipts. Capability queries must return every
|
|||
|
|
named path; missing rows, unexpected default/identity policies, wrong role,
|
|||
|
|
wrong ESO namespace/name, TTL over 5m/15m, any data write or parent/sibling/metadata
|
|||
|
|
capability fail closed. `capability_matrix_observed` means observations passed;
|
|||
|
|
`owner_acceptance: pending` is retained even when exit status is zero.
|
|||
|
|
|
|||
|
|
Operator and ESO acceptance requires ops-mason's actual owner review against the
|
|||
|
|
existing CCRs/source receipts, native role/policy/TTL observations, exact read-only
|
|||
|
|
matrix and **both** lane/query revocation confirmations. Operator role/claims
|
|||
|
|
remain grounded in the existing approved CCR-0034 binding, not a CLI role label
|
|||
|
|
chosen by the human. ESO metadata must show the fixed service account and role.
|
|||
|
|
|
|||
|
|
Nonmember never auto-passes. A semantic groups mismatch from the OIDC callback is
|
|||
|
|
only `group_refusal_candidate`; transport failure, cancellation, HTTP 403 alone,
|
|||
|
|
wrong issuer, malformed JSON, or MFA failure is `unproved_login_failure`. An
|
|||
|
|
unexpected successful nonmember login is revoked and fails the run.
|
|||
|
|
|
|||
|
|
Before ops-mason accepts check 3, key-cape supplies a value-free owner-authenticated
|
|||
|
|
identity record proving the **same attempted subject** is human, outside
|
|||
|
|
net-kingdom-admins and aal2, with validated issuer/signature/expiry; platform supplies
|
|||
|
|
a correlated native OpenBao callback refusal specifically for groups. The records
|
|||
|
|
must bind the same attempt using an owner-verified request/flow correlation digest,
|
|||
|
|
not merely nearby timestamps, a user-selected `nonmember` mode or decoded JWT
|
|||
|
|
claims. Include owner record ids/digests, observed time, subject fingerprint,
|
|||
|
|
issuer validation boolean, `group_member=false`, `aal2=true`, callback endpoint,
|
|||
|
|
refusal class and no token issued. The identity/flow digest must be produced and
|
|||
|
|
verified inside the owners' attended/audit surface; the runner does not possess
|
|||
|
|
the upstream OIDC JWT and cannot manufacture this evidence. If owners cannot
|
|||
|
|
produce this correlation, check 3 stays unproved. Never publish raw JWTs, callback
|
|||
|
|
URLs/codes/states, cookies, session ids or authentication errors.
|
|||
|
|
|
|||
|
|
This is separate from KEY-WP-0039 human/coding-agent JWT boundary evidence and
|
|||
|
|
secrets-engine's service identity denial matrix. Those do not prove this reader's
|
|||
|
|
nonmember binding. The existing successful service-jwt exchange and self-revokes
|
|||
|
|
remain accepted prior evidence; do not discard or regenerate them merely to
|
|||
|
|
complete these different gates. ops-warden may activate the pointer only after
|
|||
|
|
all T05 required owner-native receipts are actually accepted.
|
|||
|
|
|
|||
|
|
## Cleanup and failure recovery
|
|||
|
|
|
|||
|
|
On every obtained lane token, including policy mismatch/unexpected nonmember
|
|||
|
|
success, attempt lane revoke-self, then query revoke-self. A failed revoke changes
|
|||
|
|
result to unproved. A query token that fails its identity check is not trusted for
|
|||
|
|
further calls; record no cleanup confirmation and use the established founder
|
|||
|
|
revocation path. Callback timeout/malformed native auth may leave a token whose
|
|||
|
|
handle was not recovered: no cleanup success is claimed; the role's 5m/15m TTL
|
|||
|
|
bounds it and the platform owner decides recovery. No policy is widened to retry.
|
|||
|
|
|
|||
|
|
The Kubernetes TokenRequest JWT cannot be individually revoked by this procedure;
|
|||
|
|
it expires after 10m and is never persisted. Do not delete the shared ServiceAccount
|
|||
|
|
or revoke the controller's token as cleanup. No KV rollback exists because no KV
|
|||
|
|
request occurred. Session cleanup is the rollback; any unconfirmed cleanup is
|
|||
|
|
explicit open evidence and blocks acceptance until owner resolution.
|
|||
|
|
|
|||
|
|
|
|||
|
|
## Corrected source revision — 2026-10-11
|
|||
|
|
|
|||
|
|
The prior immutable stage is retained at `/tmp/mason-jwt-capability-next-stage`
|
|||
|
|
(manifest e5d4781c6280c3bc8a3930c63cfb563f59752465720d6c2c3e95eb0551f8e949).
|
|||
|
|
Independent source review requested changes: its HTTP202/text response could
|
|||
|
|
falsely confirm revocation and missing native accessors could hash the empty
|
|||
|
|
string. This revised source rejects every unsupported status/content/body/error
|
|||
|
|
shape. Lookup/capability/Kubernetes-login require HTTP200 application/json and
|
|||
|
|
endpoint-specific object data/auth, no `errors` member, with bounded headers/body.
|
|||
|
|
Revoke succeeds only on HTTP204 with an empty body. Error envelopes never imply
|
|||
|
|
cleanup; a recovered token from a mixed login envelope is retained solely for
|
|||
|
|
finally cleanup. Nonempty bounded typed actual accessors are required before
|
|||
|
|
fingerprinting; empty/malformed query accessors still revoke a scope-validated
|
|||
|
|
query token, and empty/malformed lane accessors still revoke recovered lane tokens.
|
|||
|
|
|
|||
|
|
TTL is a positive integer within the declared bound, with booleans refused.
|
|||
|
|
CLI stdout/stderr are captured while running with a 64KiB limit per stream;
|
|||
|
|
excess or timeout kills the local process group and leaves native outcome
|
|||
|
|
unproved. No unlimited capture is described as bounded. The exact approved
|
|||
|
|
source digest is checked before receipt/token/native IO. 29 offline tests cover
|
|||
|
|
these corrections, actual relative redirect refusal with hostile proxy settings,
|
|||
|
|
synthetic oversized subprocess output, valid native204 cleanup versus bad202,
|
|||
|
|
missing-accessor cleanup, and mixed-error session recovery. Source corrections
|
|||
|
|
are not a new native success, owner acceptance, founder go or adoption proof.
|