feat(sso-mfa): T05 SSO stack pivot — Keycloak → Authelia + LLDAP + KeyCape (NK-WP-0001-T05)
Replaces the Keycloak+privacyIDEA SSO tier with the lightweight stack built
during KEY-WP-0001: Authelia (password frontend), LLDAP (directory), and
KeyCape (OIDC orchestration). privacyIDEA is retained as the MFA engine.
Stack:
kc.coulomb.social — KeyCape OIDC server (stateless, custom Go)
auth.coulomb.social — Authelia login portal (password auth → Authelia OIDC → KeyCape)
lldap.coulomb.social — LLDAP admin UI (IP-restricted)
pink.coulomb.social — privacyIDEA MFA engine (unchanged)
Changes:
- Remove sso-mfa/k8s/keycloak/ (7 files)
- Add sso-mfa/k8s/lldap/ (pvc, deployment, middleware, ingress, create-secrets, README)
- Add sso-mfa/k8s/authelia/ (pvc, configmap, deployment, ingress, create-secrets, README)
- Add sso-mfa/k8s/keycape/ (deployment, middleware, ingress, create-secrets, create-pi-token, README)
- Update network-policies/netpol-sso.yaml for new component topology
- Update verify-t05.sh: checks LLDAP + Authelia + KeyCape (23 checks)
- Update CONFIG.md: fix CP-NK-004 (KeyCape), add CP-NK-005 (Authelia), CP-NK-006 (LLDAP)
- Update bootstrap/gen-secrets.sh: add LLDAP/Authelia/KeyCape sections, remove Keycloak
- Update k8s/README.md: network policy table reflects new traffic paths
- Add sso-mfa/WORKPLAN.md: resumable task checklist
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 08:31:51 +00:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
# create-secrets.sh — create the lldap-secrets K8s Secret
|
|
|
|
|
#
|
|
|
|
|
# Usage:
|
|
|
|
|
# ./create-secrets.sh [secrets-dir]
|
|
|
|
|
#
|
|
|
|
|
# <secrets-dir> is the output directory from sso-mfa/bootstrap/gen-secrets.sh
|
|
|
|
|
# (default: ../../bootstrap/secrets).
|
|
|
|
|
#
|
|
|
|
|
# Creates ONE Secret in the sso namespace:
|
|
|
|
|
# lldap-secrets — LLDAP_JWT_SECRET, LLDAP_LDAP_USER_PASS
|
|
|
|
|
#
|
|
|
|
|
# LLDAP_LDAP_USER_PASS is also used as the LDAP bind password
|
|
|
|
|
# by Authelia (authelia/create-secrets.sh) and KeyCape (keycape/create-secrets.sh).
|
|
|
|
|
# All three read the same value from secrets/lldap/secrets.env.
|
|
|
|
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
SECRETS_DIR="${1:-../../bootstrap/secrets}"
|
|
|
|
|
LLDAP_ENV="$SECRETS_DIR/lldap/secrets.env"
|
|
|
|
|
|
|
|
|
|
if [[ ! -d "$SECRETS_DIR" ]]; then
|
|
|
|
|
echo "ERROR: secrets directory not found: $SECRETS_DIR" >&2
|
|
|
|
|
echo "Run sso-mfa/bootstrap/gen-secrets.sh first." >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ ! -f "$LLDAP_ENV" ]]; then
|
|
|
|
|
echo "ERROR: $LLDAP_ENV not found" >&2
|
|
|
|
|
echo "If you ran gen-secrets.sh before the KeyCape migration, re-run it to add LLDAP secrets." >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
LLDAP_JWT_SECRET=$(bash -c "source '$LLDAP_ENV' 2>/dev/null; echo \$LLDAP_JWT_SECRET")
|
|
|
|
|
LLDAP_LDAP_USER_PASS=$(bash -c "source '$LLDAP_ENV' 2>/dev/null; echo \$LLDAP_LDAP_USER_PASS")
|
|
|
|
|
|
|
|
|
|
if [[ -z "$LLDAP_JWT_SECRET" || -z "$LLDAP_LDAP_USER_PASS" ]]; then
|
|
|
|
|
echo "ERROR: could not read LLDAP_JWT_SECRET or LLDAP_LDAP_USER_PASS from $LLDAP_ENV" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "Creating K8s Secret: lldap-secrets (namespace: sso)"
|
|
|
|
|
kubectl create secret generic lldap-secrets \
|
|
|
|
|
--namespace=sso \
|
|
|
|
|
--from-literal=LLDAP_JWT_SECRET="$LLDAP_JWT_SECRET" \
|
|
|
|
|
--from-literal=LLDAP_LDAP_USER_PASS="$LLDAP_LDAP_USER_PASS" \
|
|
|
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
|
echo "Done. Secret lldap-secrets created in namespace: sso"
|
|
|
|
|
echo ""
|
|
|
|
|
echo "Next:"
|
|
|
|
|
echo " Apply manifests (see README.md apply order)."
|
2026-07-22 15:47:26 +02:00
|
|
|
echo " After LLDAP is Running, seed groups:"
|
|
|
|
|
echo " ./bootstrap-users.sh"
|
|
|
|
|
echo " Groups: net-kingdom-users, net-kingdom-admins, activity-core-operators"
|
|
|
|
|
echo " Membership runbook: OPERATOR-GROUPS.md"
|