net-kingdom/sso-mfa/k8s/lldap
tegwick e6f4e28164
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
NK-WP-0054-T05 phase 3a: founder-run bind-split helper with end-to-end test
prepare-custody, plan, accounts and verify for ld-admin and the svc-* accounts;
named rotations for the Authelia bind and LLDAP_LDAP_USER_PASS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 308701@bnt-lap001
Assistant-Session: 5548e447-444c-4dcc-bed1-05c16eebfe56
2026-10-29 22:00:49 +01:00
..
bind-split-rehearsal.py NK-WP-0054-T05 phase 2c: Authelia refuses svc-* and ld-admin sign-in; synthetic check 2026-10-29 21:52:52 +01:00
bind-split.py NK-WP-0054-T05 phase 3a: founder-run bind-split helper with end-to-end test 2026-10-29 22:00:49 +01:00
bootstrap-users.sh security: repair LDAP group callers and fail incomplete T07 acceptance 2026-10-14 01:17:35 +02:00
break-glass.sh security: retire unsafe legacy LDAP lifecycle callers 2026-10-14 00:08:42 +02:00
create-secrets.sh fix(security): make service Secret updates private and conditional 2026-10-13 20:20:42 +02:00
create-user.sh security: retire unsafe legacy LDAP lifecycle callers 2026-10-14 00:08:42 +02:00
deployment.yaml NK-WP-0054-T05 phase 2b: each directory consumer binds with its own account 2026-10-28 20:33:04 +01:00
dry-run-nonroot-user.sh security: retire unsafe legacy LDAP lifecycle callers 2026-10-14 00:08:42 +02:00
GROUP-MAINTENANCE.md Complete NK-WP-0051 with attended member and refusal evidence 2026-10-15 19:23:19 +02:00
identity-provisioner-reconcile.py NK-WP-0054-T05 phase 2b: each directory consumer binds with its own account 2026-10-28 20:33:04 +01:00
ingress.yaml feat(sso-mfa): T05 SSO stack pivot — Keycloak → Authelia + LLDAP + KeyCape (NK-WP-0001-T05) 2026-03-19 08:31:51 +00:00
lldap_admin.py Preview one uid's directory groups for sign-in diagnosis (NK-WP-0051-T04). 2026-10-14 23:41:32 +02:00
manage-group-members.sh security: repair LDAP group callers and fail incomplete T07 acceptance 2026-10-14 01:17:35 +02:00
middleware.yaml fix(sso-mfa): use ipWhiteList for Traefik v2 in LLDAP and privacyIDEA middleware 2026-03-20 07:28:06 +00:00
OPERATOR-GROUPS.md security: repair LDAP group callers and fail incomplete T07 acceptance 2026-10-14 01:17:35 +02:00
pvc.yaml feat(sso-mfa): T05 SSO stack pivot — Keycloak → Authelia + LLDAP + KeyCape (NK-WP-0001-T05) 2026-03-19 08:31:51 +00:00
README.md security: repair LDAP group callers and fail incomplete T07 acceptance 2026-10-14 01:17:35 +02:00
test_bind_split.py NK-WP-0054-T05 phase 3a: founder-run bind-split helper with end-to-end test 2026-10-29 22:00:49 +01:00
test_identity_provisioner_reconcile.py NK-WP-0054-T05 phase 2b: each directory consumer binds with its own account 2026-10-28 20:33:04 +01:00

T05a — LLDAP (Lightweight LDAP Directory)

Exercise status: unknown for the procedures in this runbook; no per-procedure successful-run receipt with operator attribution was established in the 2026-09-05 review. See procedure inventory.

LLDAP is the user and group directory for the net-kingdom SSO stack. It provides LDAP access to Authelia (credential validation) and KeyCape (user attribute lookup). The admin web UI is IP-restricted and never exposed publicly.

Prerequisites

  • T02 complete (namespaces and NetworkPolicies applied)
  • bootstrap/gen-secrets.sh run and secrets/lldap/secrets.env populated in KeePassXC
  • kubectl configured with cluster access

Apply order

# 1. Generate secrets (if not already done)
cd ../../bootstrap && ./gen-secrets.sh

# 2. Create K8s Secret
cd ../k8s/lldap
chmod +x create-secrets.sh
./create-secrets.sh

# 3. Apply manifests (order matters)
kubectl apply -f pvc.yaml
kubectl apply -f middleware.yaml
kubectl apply -f deployment.yaml
kubectl apply -f ingress.yaml

# 4. Wait for pod to be ready
kubectl rollout status deployment/lldap -n sso --timeout=120s

Post-deploy bootstrap

After the pod is Running, preview the fixed group bootstrap under the IAM owner's authority. See group maintenance for private input, reviewed apply, preservation, interruption and native acceptance limits:

./bootstrap-users.sh --root /absolute/private/custody
# Preview only. Apply requires --apply --expected-digest from the reviewed preview.
# Groups: net-kingdom-users, net-kingdom-admins, activity-core-operators

Or create them via the web UI:

https://lldap.coulomb.social
Username: admin
Password: LLDAP_LDAP_USER_PASS (from KeePassXC → net-kingdom/LLDAP/admin)
Group Purpose
net-kingdom-users Standard users (all human accounts)
net-kingdom-admins Privileged users (KeyCape MFA step-up / extra scopes)
activity-core-operators App-scoped: browser SSO to activity-core ops + Temporal UI (Authelia domain rules). Not platform admin — grant consciously.

Operator membership (add/remove humans): see OPERATOR-GROUPS.md.

Ports

Port Protocol Access Purpose
3890 TCP (LDAP) Cluster-internal only Authelia + KeyCape LDAP bind
17170 TCP (HTTP) Traefik (IP-restricted) Admin web UI

The LDAP port is never exposed via Ingress. Only pods in the sso namespace with app.kubernetes.io/name=authelia or app.kubernetes.io/name=keycape labels are allowed to reach port 3890 (enforced by NetworkPolicy).

Secrets managed

Secret name Keys Purpose
lldap-secrets LLDAP_JWT_SECRET, LLDAP_LDAP_USER_PASS Pod environment variables

LLDAP_LDAP_USER_PASS is the admin bind password shared by Authelia and KeyCape. It must match the value used in authelia/create-secrets.sh and keycape/create-secrets.sh. All three read it from secrets/lldap/secrets.env.

Storage

lldap-data PVC (1 Gi, ReadWriteOnce) holds LLDAP's SQLite database.

Back this PVC up regularly — it contains all users and groups. If it is lost without a backup, all user accounts must be re-created and all applications must be re-enrolled in privacyIDEA.

Optional: switch to PostgreSQL by setting LLDAP_DATABASE_URL=postgresql://... env var in deployment.yaml and removing the PVC.

Verify

# Check pod status
kubectl get pod -n sso -l app.kubernetes.io/name=lldap

# Check LLDAP health via cluster-internal curl
kubectl run -n sso --rm -it ldap-test --image=busybox --restart=Never \
  -- wget -qO- http://lldap.sso.svc.cluster.local:17170/health

# Test LDAP bind (from another pod in the sso namespace)
# ldapwhoami -H ldap://lldap.sso.svc.cluster.local:3890 \
#   -D "uid=admin,ou=people,dc=netkingdom,dc=local" -w <LLDAP_LDAP_USER_PASS>