Files
net-kingdom/sso-mfa/bootstrap/gen-secrets.sh
tegwick c5761884f4 feat(sso-mfa): Phase 0a bootstrap tooling (NK-WP-0001-T01)
- sso-mfa/bootstrap/gen-secrets.sh: generates all pre-cluster secrets
  (PI_SECRET_KEY, PI_PEPPER, DB passwords, Keycloak admin, break-glass)
  into a structured secrets/ directory; prints summary with truncated values.
  PI_ENCFILE deferred — must be generated inside the privacyIDEA container.
- sso-mfa/bootstrap/pack-bundle.sh: age-encrypts the secrets directory into
  an offsite ops bundle.
- sso-mfa/bootstrap/README.md: KeePassXC group/entry structure, full workflow
  (generate → KeePassXC → bundle → shred → PI_ENCFILE post-deploy).
- .gitignore: add sso-mfa/bootstrap/secrets/, *.age, *.kdbx.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 09:01:50 +01:00

135 lines
6.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# gen-secrets.sh — generate all bootstrap secrets for the net-kingdom SSO/MFA platform
#
# Usage:
# ./gen-secrets.sh [OUTPUT_DIR]
#
# Generates all pre-cluster secrets and writes them to OUTPUT_DIR (default: ./secrets).
# Output files are structured by component to mirror the KeePassXC entry layout.
#
# WARNING: The secrets/ directory must NEVER be committed to git.
# After entering values into KeePassXC, shred the generated files:
# find secrets/ -type f -exec shred -u {} \;
#
# PI_ENCFILE is NOT generated here — it must be produced inside the privacyIDEA
# container after deployment:
# kubectl exec -n mfa <pi-pod> -- pi-manage create_enckey
# Extract the resulting file, store it in KeePassXC as a binary attachment on the
# privacyIDEA/PI_ENCFILE entry, then create the k8s secret from it.
set -euo pipefail
OUT_DIR="${1:-./secrets}"
if [[ -e "$OUT_DIR" ]]; then
echo "ERROR: $OUT_DIR already exists. Delete it first or choose a different path." >&2
exit 1
fi
# Helpers
rnd_hex() { openssl rand -hex "$1"; }
rnd_b64() { openssl rand -base64 "$1" | tr -d '\n/+=' | head -c "$2"; }
mkdir -p \
"$OUT_DIR/privacyidea" \
"$OUT_DIR/postgres" \
"$OUT_DIR/keycloak" \
"$OUT_DIR/breakglass"
# ── privacyIDEA ────────────────────────────────────────────────────────────────
PI_SECRET_KEY="$(rnd_hex 32)" # 64 hex chars — Flask/PI app secret
PI_PEPPER="$(rnd_hex 16)" # 32 hex chars — password hashing pepper
PI_DB_PASS="$(rnd_b64 32 40)" # 40 printable chars — DB password
PI_ADMIN_PASS="$(rnd_b64 32 40)"
cat > "$OUT_DIR/privacyidea/secrets.env" <<EOF
# privacyIDEA secrets — KeePassXC group: net-kingdom/privacyIDEA
# Entry: pi-admin → username=pi-admin password=PI_ADMIN_PASSWORD
# Entry: database → username=privacyidea password=PI_DB_PASSWORD
# Entry: SECRET_KEY → password=PI_SECRET_KEY (no username)
# Entry: PI_PEPPER → password=PI_PEPPER (no username)
# Entry: PI_ENCFILE → binary attachment (generate AFTER container deploy)
PI_SECRET_KEY=$PI_SECRET_KEY
PI_PEPPER=$PI_PEPPER
PI_DB_PASSWORD=$PI_DB_PASS
PI_ADMIN_PASSWORD=$PI_ADMIN_PASS
# PI_ENCFILE: generate with:
# kubectl exec -n mfa <pi-pod> -- pi-manage create_enckey
# kubectl cp -n mfa <pi-pod>:/etc/privacyidea/enckey ./secrets/privacyidea/pi.enc
# Then store pi.enc as a binary attachment in KeePassXC → net-kingdom/privacyIDEA/PI_ENCFILE
EOF
# ── PostgreSQL ─────────────────────────────────────────────────────────────────
PG_ROOT_PASS="$(rnd_b64 32 40)"
PG_KC_PASS="$(rnd_b64 32 40)"
# privacyIDEA DB user reuses PI_DB_PASS (single source of truth)
cat > "$OUT_DIR/postgres/secrets.env" <<EOF
# PostgreSQL secrets — KeePassXC group: net-kingdom/PostgreSQL
# Entry: postgres root → username=postgres password=PG_ROOT_PASSWORD
# Entry: keycloak user → username=keycloak password=PG_KEYCLOAK_PASSWORD
# Entry: privacyidea user → username=privacyidea password=PI_DB_PASSWORD (copy from privacyIDEA entry)
PG_ROOT_PASSWORD=$PG_ROOT_PASS
PG_KEYCLOAK_PASSWORD=$PG_KC_PASS
# PI_DB_PASSWORD is in privacyidea/secrets.env — do NOT copy here; link in KeePassXC
EOF
# ── Keycloak ───────────────────────────────────────────────────────────────────
KC_ADMIN_PASS="$(rnd_b64 32 40)"
# Keycloak DB password == PG_KEYCLOAK_PASSWORD (single source of truth)
cat > "$OUT_DIR/keycloak/secrets.env" <<EOF
# Keycloak secrets — KeePassXC group: net-kingdom/Keycloak
# Entry: admin → username=admin password=KC_ADMIN_PASSWORD
# Entry: database → username=keycloak password=KC_DB_PASSWORD (copy from postgres/keycloak user)
KC_ADMIN_PASSWORD=$KC_ADMIN_PASS
KC_DB_PASSWORD=$PG_KC_PASS
EOF
# ── Break-glass ────────────────────────────────────────────────────────────────
BG_PASS="$(rnd_b64 32 40)"
cat > "$OUT_DIR/breakglass/secrets.env" <<EOF
# Break-glass secrets — KeePassXC group: net-kingdom/Break-glass
# Entry: break-glass → username=break-glass password=BREAKGLASS_PASSWORD
# Entry: recovery-otp → TOTP seed (enroll manually after Keycloak is up)
BREAKGLASS_PASSWORD=$BG_PASS
EOF
# ── Summary ────────────────────────────────────────────────────────────────────
echo "=== net-kingdom SSO/MFA bootstrap secrets ==="
echo "Generated: $(date -Iseconds)"
echo "Output : $OUT_DIR/"
echo ""
echo " privacyIDEA:"
echo " PI_SECRET_KEY : $(wc -c < "$OUT_DIR/privacyidea/secrets.env" > /dev/null; echo "${PI_SECRET_KEY:0:16}")"
echo " PI_PEPPER : ${PI_PEPPER:0:8}"
echo " PI_DB_PASSWORD : ${PI_DB_PASS:0:8}"
echo " PI_ADMIN_PASSWORD: ${PI_ADMIN_PASS:0:8}"
echo " PI_ENCFILE : *** generate after container deploy (see comments) ***"
echo ""
echo " PostgreSQL:"
echo " PG_ROOT_PASSWORD : ${PG_ROOT_PASS:0:8}"
echo " PG_KEYCLOAK_PASSWORD: ${PG_KC_PASS:0:8}"
echo " PG_PI_PASSWORD : (same as PI_DB_PASSWORD)"
echo ""
echo " Keycloak:"
echo " KC_ADMIN_PASSWORD: ${KC_ADMIN_PASS:0:8}"
echo " KC_DB_PASSWORD : (same as PG_KEYCLOAK_PASSWORD)"
echo ""
echo " Break-glass:"
echo " BREAKGLASS_PASSWORD: ${BG_PASS:0:8}"
echo ""
echo "Next steps:"
echo " 1. Enter each value into KeePassXC (see comments in each secrets.env file)."
echo " 2. Run pack-bundle.sh to create an age-encrypted offsite backup."
echo " 3. Shred the generated files:"
echo " find $OUT_DIR -type f -exec shred -u {} \\;"
echo ""
echo "NEVER commit $OUT_DIR/ to git."