From 145ca8e08c6f1a390341b9bea9b1d69c0024031d Mon Sep 17 00:00:00 2001 From: tegwick Date: Wed, 28 Oct 2026 20:33:04 +0100 Subject: [PATCH] NK-WP-0054-T05 phase 2b: each directory consumer binds with its own account Custody gains LLDAP_SVC_{AUTHELIA,KEYCAPE,PRIVACYIDEA,PROVISIONER}_PASS and LLDAP_LDAP_USER_PASS becomes ld-admin's. Authelia, KeyCape, the privacyIDEA resolver and identity-provisioner (new Secret identity-provisioner-ldap) switch to svc-* accounts; LLDAP's configured super-admin is ld-admin. The LLDAP image pin waits for the running digest. Co-Authored-By: Claude Opus 5.5 Assistant: claude-code Assistant-Model: opus Assistant-Process: 308701@bnt-lap001 Assistant-Session: 5548e447-444c-4dcc-bed1-05c16eebfe56 --- sso-mfa/bootstrap/apply-service-secrets.py | 5 ++++- sso-mfa/bootstrap/creds-rotate.sh | 2 +- sso-mfa/bootstrap/gen-secrets.sh | 19 +++++++++++++++---- sso-mfa/k8s/authelia/configmap.yaml | 2 +- .../identity-provisioner/create-secrets.sh | 7 +++++++ .../k8s/identity-provisioner/deployment.yaml | 6 +++++- sso-mfa/k8s/keycape/bootstrap-config.json | 2 +- sso-mfa/k8s/keycape/create-secrets.py | 2 +- sso-mfa/k8s/lldap/deployment.yaml | 7 ++++++- .../lldap/identity-provisioner-reconcile.py | 9 +++++---- .../test_identity_provisioner_reconcile.py | 4 ++-- sso-mfa/k8s/privacyidea/realm_bootstrap.py | 4 ++-- tests/test_keycape_bootstrap.py | 4 ++-- tests/test_privacyidea_verification.py | 6 +++--- tests/test_realm_bootstrap.py | 2 +- tests/test_service_secret_custody.py | 10 ++++++---- .../NK-WP-0054-service-identity-policy.md | 14 ++++++++++++++ 17 files changed, 76 insertions(+), 29 deletions(-) create mode 100644 sso-mfa/k8s/identity-provisioner/create-secrets.sh diff --git a/sso-mfa/bootstrap/apply-service-secrets.py b/sso-mfa/bootstrap/apply-service-secrets.py index 6c41a93..1e78a92 100644 --- a/sso-mfa/bootstrap/apply-service-secrets.py +++ b/sso-mfa/bootstrap/apply-service-secrets.py @@ -25,6 +25,7 @@ TARGETS = { 'privacyidea': ('mfa', 'privacyidea-config', ('privacyidea',)), 'lldap': ('sso', 'lldap-secrets', ('lldap',)), 'authelia': ('sso', 'authelia-secrets', ('authelia', 'lldap')), + 'identity-provisioner': ('sso', 'identity-provisioner-ldap', ('lldap',)), } ROTATIONS = { 'postgresql': {'PI_DB_PASSWORD': 'password'}, @@ -167,12 +168,14 @@ def service_values(component, values): '@net-kingdom-pg-rw.databases.svc.cluster.local:5432/privacyidea_db'} if component == 'lldap': return {key: literal(values['lldap'], key) for key in ('LLDAP_JWT_SECRET', 'LLDAP_LDAP_USER_PASS')} + if component == 'identity-provisioner': + return {'username': 'svc-provisioner', 'password': literal(values['lldap'], 'LLDAP_SVC_PROVISIONER_PASS')} env = values['authelia'] return {'jwt_secret': literal(env, 'AUTHELIA_JWT_SECRET'), 'session_secret': literal(env, 'AUTHELIA_SESSION_SECRET'), 'storage_encryption_key': literal(env, 'AUTHELIA_STORAGE_ENCRYPTION_KEY'), 'oidc_hmac_secret': literal(env, 'AUTHELIA_OIDC_HMAC_SECRET'), - 'ldap_password': literal(values['lldap'], 'LLDAP_LDAP_USER_PASS')} + 'ldap_password': literal(values['lldap'], 'LLDAP_SVC_AUTHELIA_PASS')} def publish(namespace, name, desired, old, allowed): diff --git a/sso-mfa/bootstrap/creds-rotate.sh b/sso-mfa/bootstrap/creds-rotate.sh index f03259f..4da9b51 100755 --- a/sso-mfa/bootstrap/creds-rotate.sh +++ b/sso-mfa/bootstrap/creds-rotate.sh @@ -279,7 +279,7 @@ BREAKGLASS_PASSWORD) echo " PI_PEPPER Password hashing pepper (PERMANENT — read help)" echo " PI_DB_PASSWORD privacyIDEA database password" echo " LLDAP_JWT_SECRET LLDAP JWT signing key" - echo " LLDAP_LDAP_USER_PASS LLDAP admin + LDAP bind password (3-way coordinated)" + echo " LLDAP_LDAP_USER_PASS ld-admin, LLDAP configured super-admin (refused here)" echo " AUTHELIA_SESSION_SECRET Authelia session cookie key" echo " AUTHELIA_KEYCAPE_CLIENT_SECRET Authelia↔KeyCape OIDC client secret" echo " KEYCAPE_RSA_KEY KeyCape JWT signing key (causes auth outage)" diff --git a/sso-mfa/bootstrap/gen-secrets.sh b/sso-mfa/bootstrap/gen-secrets.sh index c9e45a0..4c2f815 100755 --- a/sso-mfa/bootstrap/gen-secrets.sh +++ b/sso-mfa/bootstrap/gen-secrets.sh @@ -81,18 +81,29 @@ EOF # ── LLDAP ────────────────────────────────────────────────────────────────────── LLDAP_JWT_SECRET="$(rnd_hex 32)" # 64 hex chars — LLDAP JWT signing key -LLDAP_LDAP_USER_PASS="$(rnd_b64 32 40)" # 40 printable chars — LLDAP admin + Authelia/KeyCape bind password +LLDAP_LDAP_USER_PASS="$(rnd_b64 32 40)" # 40 printable chars — ld-admin, LLDAP's configured super-admin (sealed fallback) +# Per-consumer directory accounts (Service Identity SI-3, NK-WP-0054-T05). The human `admin` +# password is personal and is never generated into custody. +LLDAP_SVC_AUTHELIA_PASS="$(rnd_b64 32 40)" # svc-authelia, read-only bind +LLDAP_SVC_KEYCAPE_PASS="$(rnd_b64 32 40)" # svc-keycape, read-only bind +LLDAP_SVC_PRIVACYIDEA_PASS="$(rnd_b64 32 40)" # svc-privacyidea, read-only resolver bind +LLDAP_SVC_PROVISIONER_PASS="$(rnd_b64 32 40)" # svc-provisioner, lldap_admin (exception SI-X6) cat > "$OUT_DIR/lldap/secrets.env" <