Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a06ea3-7939-7b63-8125-699f8b50bedd
6.5 KiB
KeyCape exposure: privacyIDEA resolver reconciliation
Incident: KEYCAPE-EXPOSURE-20260823-01
Workplan: NK-WP-0033
NetKingdom procedure: sso-mfa/k8s/privacyidea/reconcile-lldap-resolver-live.sh (repaired 2026-08-27 in 4a38511; the previously pinned revision could not complete a run — see NK-WP-0033 T05)
Platform recovery contract: railiance-platform 453fed3
Owner cutover receipt: State Hub message 45b236c8-052f-43d3-a472-44f8e9694da2
Exercise status: unexercised to successful completion — attempted 2026-08-27 by Bernd Worsch; four defects found and fixed (4a38511), no green receipt. The 2026-09-05 shared transport refactor also awaits an attended run. See attended-procedure-standard.md.
This is the remaining attended provider-admin operation after the owner-reported
four-class cutover. It updates only privacyIDEA resolver lldap-coulomb so the
resolver uses the replacement LLDAP bind credential. It does not modify realms,
policies, tokens, KeyCape Secrets, or any other resolver.
No password, hash, token, Secret payload, or manifest belongs in this document, State Hub, Git, chat, command arguments, or ordinary logs.
Authority and pinning gate
The operator must record a private approval receipt containing, at minimum:
- incident
KEYCAPE-EXPOSURE-20260823-01; - the NetKingdom revision containing
reconcile-lldap-resolver-live.shand its adjacentpi_api.pyand platform contract453fed3; - the owner receipt
45b236c8-052f-43d3-a472-44f8e9694da2; - the exact start/end window, attended driver, and independent abort operator;
- confirmation that the replacement LLDAP credential is the provider-approved value and that no exposed predecessor will be restored.
No live action is permitted if any revision, owner, cluster, or approval identifier differs from the receipt.
Preflight (metadata and health only)
Run from the approved operator workstation, with the cluster context and provider endpoint already authorized. Do not render any Secret data.
- Verify the approved checkout contains
reconcile-lldap-resolver-live.shwith mode0755; inspect its source, not live credential material. - Confirm LLDAP, privacyIDEA, KeyCape, Authelia, and identity-provisioner are Ready using deployment/pod status fields only.
- Confirm privacyIDEA availability via the documented unauthenticated
/token/probe (401/403 is expected) and KeyCape discovery health, discarding response bodies. Do not use a command that prints a bearer token or configuration response. - Confirm the approved window, driver, abort operator, provider custody, and cleanup workspace are ready. Stop on any drift or missing owner.
Apply (one attended operation)
-
From the approved checkout, run exactly:
bash sso-mfa/k8s/privacyidea/reconcile-lldap-resolver-live.sh --applyThe helper securely prompts for pi-admin, replacement and predecessor LLDAP passwords, and one approved MFA code; authenticates to privacyIDEA; performs exactly one
POST /resolver/lldap-coulomb; proves replacement resolver lookup, privacyIDEA MFA, replacement LLDAP authentication, and predecessor denial; rechecks readiness/health; securely cleans up; and emits one sanitized PASS/FAIL receipt. It must not be combined withrepair-realm-live.sh,bootstrap-realm.sh,creds-rotate.sh, or any full-bundle generator. -
Stop immediately on any non-success response, timeout, unexpected endpoint, or failed cleanup. Do not restore the exposed bundle or predecessor credential.
Postflight and predecessor denial
Record only status codes, readiness, timestamps, revision identifiers, and boolean results.
- Confirm privacyIDEA, LLDAP, KeyCape, Authelia, and identity-provisioner are Ready again. Confirm the privacyIDEA health endpoint succeeds and the resolver endpoint returns success without retaining its response body.
- Exercise one approved KeyCape MFA path that requires the
coulombrealm. Record pass/fail only; never record the token or response body. - Using protected file inputs, prove an LDAP bind with the replacement value succeeds and a bind with the exposed predecessor fails. The predecessor test must be a boolean result and must not put the password in argv or stdout. A failed predecessor bind is required evidence; do not retry it against another provider.
- Confirm the KeyCape owner’s existing four-class positive/negative receipt remains associated with this resolver update. If any class lacks a receipt, keep T05 open.
- Securely remove the temporary workspace and record only cleanup success.
Abort and rollback
Abort before mutation on revision drift, missing authority, unavailable health, uncertain workspace cleanup, or any unsafe helper output. Abort forward after mutation on a failed resolver response, failed readiness, failed replacement MFA, or missing predecessor denial. The exposed bundle and every exposed predecessor are never rollback material. Recovery after a partial write must use a newly approved replacement value and revision, not a stale local bundle.
Completion evidence
T03 may move to done only after the helper run and cleanup receipt are recorded by the attended operator. T05 may move to done only after the resolver’s replacement success, predecessor denial, owner cutover receipt, and all residual limitations are recorded as sanitized evidence.
Revision note — 2026-08-27
The pinned revision of reconcile-lldap-resolver-live.sh had never completed a
run. Four defects were found by running it and are fixed in 4a38511; see
NK-WP-0033 T05 for the full findings. Two change how this procedure is
invoked:
--predecessor-unavailable— use when the exposed predecessor cannot be produced. The denial bind is not attempted and the receipt recordspredecessor denial=NOT-PROVEN. Do not type a placeholder at the predecessor prompt instead: a wrong value also fails the bind, and the run records it as a passing denial proof — a receipt asserting a test that never ran.--note TEXT— operator context carried verbatim in the receipt line, so a claim and its caveat travel together. One line, 200 characters, no credentials.
TIMEOUT, CACHE_TIMEOUT and SIZELIMIT are now sent with the resolver body
(default 5 / 120 / 500, overridable via the matching LDAP_* environment
variables). Before this fix, --apply dropped them, because a resolver write
replaces the whole object. A resolver with them unset still resolves users, but
the WebUI refuses to save or test it — so a hand repair was silently reverted by
the next run.