Files
net-kingdom/sso-mfa/k8s/keycape/create-secrets.sh
Bernd Worsch 0754dc32e6 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

128 lines
4.9 KiB
Bash

#!/usr/bin/env bash
# create-secrets.sh — create the keycape-config K8s Secret
#
# Usage:
# ./create-secrets.sh [secrets-dir]
#
# Creates ONE Secret in the sso namespace:
# keycape-config — config.yaml (full KeyCape config) + key.pem (RSA signing key)
#
# The privacyIDEA admin token is a separate Secret (keycape-pi-token) created
# by create-pi-token.sh AFTER privacyIDEA is bootstrapped (T04 complete).
# The PI admin token is read from that Secret at startup via config.yaml.
#
# Re-run this script to:
# - Rotate the Authelia client secret (update secrets/authelia/secrets.env first)
# - Add or modify OIDC client registrations (edit CLIENTS block below)
# - Rotate the RSA signing key (delete and regenerate secrets/keycape/key.pem)
set -euo pipefail
SECRETS_DIR="${1:-../../bootstrap/secrets}"
KEYCAPE_ENV="$SECRETS_DIR/keycape/secrets.env"
LLDAP_ENV="$SECRETS_DIR/lldap/secrets.env"
AUTHELIA_ENV="$SECRETS_DIR/authelia/secrets.env"
KEY_FILE="$SECRETS_DIR/keycape/key.pem"
for f in "$KEYCAPE_ENV" "$LLDAP_ENV" "$AUTHELIA_ENV"; do
if [[ ! -f "$f" ]]; then
echo "ERROR: $f not found — run sso-mfa/bootstrap/gen-secrets.sh first." >&2
exit 1
fi
done
read_env() { bash -c "source '$1' 2>/dev/null; echo \${$2}"; }
LLDAP_BIND_PW=$(read_env "$LLDAP_ENV" LLDAP_LDAP_USER_PASS)
AUTHELIA_CLIENT_SECRET=$(read_env "$AUTHELIA_ENV" AUTHELIA_KEYCAPE_CLIENT_SECRET)
if [[ -z "$LLDAP_BIND_PW" || -z "$AUTHELIA_CLIENT_SECRET" ]]; then
echo "ERROR: could not read LLDAP_LDAP_USER_PASS or AUTHELIA_KEYCAPE_CLIENT_SECRET" >&2
exit 1
fi
# The privacyIDEA admin token is read from a separate Secret at runtime.
# Placeholder here — create-pi-token.sh populates the real value.
PI_ADMIN_TOKEN="PENDING_create-pi-token.sh"
if [[ -f "$SECRETS_DIR/keycape/pi_admin_token" ]]; then
PI_ADMIN_TOKEN=$(cat "$SECRETS_DIR/keycape/pi_admin_token")
echo "INFO: Using privacyIDEA admin token from $SECRETS_DIR/keycape/pi_admin_token"
fi
# ── RSA signing key ───────────────────────────────────────────────────────────
if [[ ! -f "$KEY_FILE" ]]; then
echo "Generating RSA-2048 signing key for KeyCape JWT tokens..."
mkdir -p "$(dirname "$KEY_FILE")"
openssl genrsa -out "$KEY_FILE" 2048 2>/dev/null
chmod 600 "$KEY_FILE"
echo " Generated: $KEY_FILE"
echo " IMPORTANT: Store this key in KeePassXC → net-kingdom/KeyCape/jwt-signing-key"
echo " as a binary attachment. It cannot be recovered if lost."
else
echo "INFO: Using existing key: $KEY_FILE"
fi
KEY_CONTENT=$(cat "$KEY_FILE")
# ── Build config.yaml ─────────────────────────────────────────────────────────
# Edit the OIDC clients block below to register downstream applications.
# Re-run this script after any change.
CONFIG_YAML=$(cat <<EOF
issuer: "https://kc.coulomb.social"
port: 8080
tokenLifetime: "15m"
privateKeyPem: "/etc/keycape/key.pem"
environment: "production"
lldap:
url: "ldap://lldap.sso.svc.cluster.local:3890"
bindDN: "uid=admin,ou=people,dc=netkingdom,dc=local"
bindPW: "${LLDAP_BIND_PW}"
baseDN: "dc=netkingdom,dc=local"
authelia:
baseURL: "http://authelia.sso.svc.cluster.local:9091"
clientId: "keycape"
clientSecret: "${AUTHELIA_CLIENT_SECRET}"
redirectURI: "https://kc.coulomb.social/authorize/callback"
privacyidea:
baseURL: "http://privacyidea.mfa.svc.cluster.local:8080"
adminToken: "${PI_ADMIN_TOKEN}"
realm: "netkingdom"
# ── OIDC client registrations ─────────────────────────────────────────────────
# Add one entry per downstream application.
# clientType: "public" for SPAs/native apps (PKCE, no client secret)
# "confidential" for server-side apps (client secret required)
clients: []
# Example:
# clients:
# - clientId: "my-app"
# displayName: "My Application"
# redirectUris:
# - "https://my-app.coulomb.social/callback"
# allowedScopes: ["openid", "profile", "email", "groups"]
# grantTypes: ["authorization_code"]
# clientType: "public"
EOF
)
echo "Creating K8s Secret: keycape-config (namespace: sso)"
kubectl create secret generic keycape-config \
--namespace=sso \
--from-literal=config.yaml="$CONFIG_YAML" \
--from-literal=key.pem="$KEY_CONTENT" \
--dry-run=client -o yaml | kubectl apply -f -
echo ""
echo "Done. Secret keycape-config created in namespace: sso"
echo ""
if [[ "$PI_ADMIN_TOKEN" == "PENDING_create-pi-token.sh" ]]; then
echo "WARN: privacyIDEA admin token is a placeholder."
echo " After T04 bootstrap is complete, run:"
echo " ./create-pi-token.sh"
echo " Then re-run this script to update keycape-config."
echo ""
fi
echo "Next: apply deployment.yaml, middleware.yaml, ingress.yaml"