generated from coulomb/repo-seed
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>
This commit is contained in:
127
sso-mfa/k8s/keycape/create-secrets.sh
Normal file
127
sso-mfa/k8s/keycape/create-secrets.sh
Normal file
@@ -0,0 +1,127 @@
|
||||
#!/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"
|
||||
Reference in New Issue
Block a user