diff --git a/docs/evidence/2026-10-30-nk54-bind-split/README.md b/docs/evidence/2026-10-30-nk54-bind-split/README.md index 117c36e..5ad339a 100644 --- a/docs/evidence/2026-10-30-nk54-bind-split/README.md +++ b/docs/evidence/2026-10-30-nk54-bind-split/README.md @@ -36,5 +36,15 @@ UTC, agent (Claude Code) guiding. All receipts are value-free (`values_recorded: 4. Rollouts of identity-provisioner, KeyCape and LLDAP use `Recreate`: each had a short outage of about 30 s. +5. **privacyIDEA resolver was still bound as `admin` (found 2026-10-30 evening).** After step 10 + every OTP check failed: KeyCape logged `mfa_failed` (`openbao-admin`) and `mfa_check_error` + (`user-engine-portal`); privacyIDEA logged `LDAP Bind unsuccessful: invalidCredentials (49)` from + 19:00:10 UTC, last successful lookup 18:49:30 UTC, step 10 at 18:53 UTC. Founder found Bind DN + `uid=admin,…` on `lldap-coulomb` in the privacyIDEA UI, set `uid=svc-privacyidea,…` with the custody + `LLDAP_SVC_PRIVACYIDEA_PASS`, and **Test LDAP Resolver** passed. No repository tool rewrites the + resolver, so step 8's apply most likely did not take effect; its OTP check passed only because the + old shared password was still valid. Runbook step 8 now requires the resolver Bind DN and test, and + step 10 a fresh OTP sign-in. + Closing condition still open: the restore drill on the first backup generation after this run (NK-WP-0053 stages 2-5, T17/T19 under the new accounts). diff --git a/sso-mfa/k8s/lldap/BIND-SPLIT-RUNBOOK.md b/sso-mfa/k8s/lldap/BIND-SPLIT-RUNBOOK.md index c2aec0a..a5689a3 100644 --- a/sso-mfa/k8s/lldap/BIND-SPLIT-RUNBOOK.md +++ b/sso-mfa/k8s/lldap/BIND-SPLIT-RUNBOOK.md @@ -136,7 +136,11 @@ portal or the OpenBao UI through `openbao-ui-railiance01`). Rollback: the same t python3 sso-mfa/k8s/privacyidea/realm_bootstrap.py "$CUSTODY" --switch-bind # preview python3 sso-mfa/k8s/privacyidea/realm_bootstrap.py "$CUSTODY" --switch-bind --apply ``` -Expect `actions: ["switch-bind"]`, one write. Check: a sign-in with OTP (step 6 again). There is no +Expect `actions: ["switch-bind"]`, one write; a `"result":"unverified"` line on stderr means it did not +apply. Check: as `pi-admin`, Config → Users → `lldap-coulomb` shows Bind DN +`uid=svc-privacyidea,…` and **Test LDAP Resolver** passes. An OTP sign-in alone does not prove the +switch: until step 10 retires the old password a resolver still bound as `admin` keeps working +(2026-10-30 incident, `docs/evidence/2026-10-30-nk54-bind-split/README.md`). There is no automated rollback; the old bind is the `admin` account, which still works, so the attended repair (`--attended`, prompts) can set it back if needed. @@ -157,7 +161,8 @@ Sign in to the LLDAP UI as `admin`, change your password, store it in your passw python3 sso-mfa/k8s/lldap/bind-split.py verify --endpoint https://lldap.coulomb.social "$CUSTODY" --old-admin-retired --receipt ~/nk54/10-verify.json ``` It prompts for the new `admin` password, then the old shared one, and requires that the old one is -refused. `"verdict": "pass"` ends the live run. +refused. `"verdict": "pass"` ends the live run once a fresh OTP sign-in still succeeds afterwards +(this is the first check that no consumer still binds with the old shared password). ## 11. Afterwards