Assistant: codex Assistant-Model: gpt-5.6-luna Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
78 lines
4.9 KiB
Markdown
78 lines
4.9 KiB
Markdown
# KeyCape approval-client rollout and recovery
|
|
|
|
Accepted 2026-09-09 under CCR-2026-0017 and CCR-2026-0018. Both service
|
|
registrations are live on one ready KeyCape replica. The existing human OpenBao
|
|
login passed after replacement. [Live receipt](evidence/2026-09-09-keycape-verifier-admission.json).
|
|
The [attempt receipts](evidence/2026-09-09-keycape-activation-attempts.json) retain
|
|
failed checks and confirmed compatible rollback; no failed attempt is counted
|
|
as activation. Both OpenBao values remain at their initial version 1.
|
|
|
|
The source image is the immutable manifest
|
|
`forgejo.coulomb.social/coulomb/key-cape@sha256:7ff54c54e63ee172ae9e6e7fd2da96e427352f712343d74626ee6fe0f6f82611`.
|
|
Deployment authority is `sso-mfa/k8s/keycape/deployment.yaml`; the live config
|
|
remains in `sso/keycape-config`. The contained helper appends only the two
|
|
reviewed client registrations and preserves the signing key and every unrelated
|
|
configuration byte. It uses UID/resourceVersion tests for config and deployment
|
|
mutations, and retains the previous compatible pair in protected owner storage.
|
|
|
|
The platform command `scripts/keycape_approval_custody.py` opens through
|
|
`openbao-attended-exec.py` and the governed Warden `openbao-platform-admin-login`
|
|
envelope. It owns approved policies/roles, CAS=0 first provision, ESO delivery,
|
|
native scope/auth/namespace denials and reader revocation. It invokes this
|
|
repository's `sso-mfa/k8s/keycape/approval-clients-rollout.py` for image/config
|
|
replacement and service acceptance. Do not run the platform child directly.
|
|
On this workstation the verified Railiance kubeconfig is
|
|
`/home/worsch/.kube/config-railiance01`; the default config targets another endpoint.
|
|
|
|
Use `activate` only for a first provision with absent custody and delivery.
|
|
`resume-activate --prior-receipt <metadata receipt>` requires a completed compatible
|
|
rollback, unchanged version-1 custody, unchanged policies and detached reader roles.
|
|
It reattaches the same readers without writing any value. Both actions require a
|
|
unique `--receipt` and `--recovery` path. Successful service acceptance is followed
|
|
by a fresh attended login running the owner helper's `verify-after-login` action.
|
|
Existing active custody can be rechecked with the platform helper's `verify`
|
|
action. Repeating first provision against active custody is deliberately refused.
|
|
|
|
The verifier binary comes from the pinned image, without starting its extraction
|
|
container. Install it in the owner-protected path
|
|
`~/.local/share/key-cape/verified-bin/dcebd46/keycape` with mode 0700. Its SHA-256
|
|
must be `4bf93bbe9afe0bf2e21d51c03373a7e2b4be6864586bcc2d472eeb9abc913d92`;
|
|
the helper checks this before custody mutation and before each verifier run.
|
|
Extraction needs only `docker create`, `docker cp <container>:/keycape <private path>`,
|
|
and removal of that never-started container. No credential enters that container.
|
|
|
|
Run the native verifier in the existing attended owner process. It receives the
|
|
same verifier-side credential already read privately for independent JWT checks,
|
|
through a child environment that is never printed or written to a file. The
|
|
KeyCape pod's internal-only egress policy does not admit its public HTTPS issuer;
|
|
this rollout makes no network-policy change. Container readiness checks the
|
|
manifest digest in `imageID`, since containerd's `image` field can hold a different
|
|
runtime configuration digest.
|
|
|
|
Independent JWT checks match the existing native contract: at most 30 seconds
|
|
of future issued-at time, strict not-before and expiry, exact audience/subject/
|
|
tenant/role/scope and a 900-second lifetime. Global JWT leeway is not used.
|
|
Wrong secrets and excess scopes require the exact issuer HTTP status/error/feature.
|
|
The public human OpenBao client is also denied `approval:consume`.
|
|
|
|
Reproducible preparation checks:
|
|
|
|
```sh
|
|
python3 -B sso-mfa/k8s/keycape/test_approval_clients_rollout.py
|
|
python3 -B sso-mfa/k8s/keycape/exercise-approval-clients.py --receipt /tmp/<unique-scratch-receipt>.json
|
|
```
|
|
|
|
The second command requires Docker, the installed pinned verifier, PyYAML,
|
|
PyJWT and cryptography. It runs the pinned image behind loopback HTTPS with
|
|
synthetic signing keys and client credentials, including the native verifier.
|
|
It removes its container, TLS server and temporary credential files. It neither
|
|
reads production config nor opens an attended login. The platform's
|
|
`tests/test_keycape_approval_custody.py` separately exercises real ACLs, CAS=0,
|
|
revocation and version-preserving resume against disposable local OpenBao.
|
|
|
|
KEY-WP-0013-T02 is complete. KEY-WP-0013-T05 retains the approval UI's callback
|
|
and MFA/PKCE acceptance. Separate client-side delivery remains RPF-WP-0035-T05;
|
|
audit custody remains AUDIT-WP-0009-T09; claim/consume and native execution proof
|
|
remain APPROVAL-WP-0002 and SECRETS-WP-0009-T03. Initial provisioning did not
|
|
exercise natural JWT expiry or actual predecessor rotation. HFACT-WP-0001 retains
|
|
factory execution/grant/spend admission and Railiance worker acceptance.
|