108 lines
4.0 KiB
Bash
108 lines
4.0 KiB
Bash
#!/usr/bin/env bash
|
||
# Authentik — zentraler Homelab-IdP (nexus ADR-0003)
|
||
#
|
||
# Creates an unprivileged Debian 12 LXC with nesting enabled that runs the
|
||
# official Authentik docker-compose stack (server, worker, postgres, redis).
|
||
#
|
||
# Automation-friendly by design (nexus-hub K-102):
|
||
# - bootstrap admin password AND API token are generated headlessly
|
||
# (-> /root/authentik.credentials) so an agent can apply blueprints via
|
||
# API without ever touching the UI
|
||
# - optional dedicated SSH public key for agent access (Claude Code)
|
||
# - blueprints dir mounted at /opt/authentik/blueprints (compose override)
|
||
#
|
||
# Manual steps that remain AFTER this script (by design):
|
||
# 1. NPMplus: proxy host auth.<domain> -> http://<LXC-IP>:9000
|
||
# (WebSockets ON; the auth domain is PERMANENT — WebAuthn RP-ID!)
|
||
# 2. Passkey enrollment of the human admin account
|
||
#
|
||
# Run on a Proxmox VE host:
|
||
# bash -c "$(curl -fsSL https://gitea.luki-net.org/luki-net/proxmox-scripts/raw/branch/main/ct/authentik.sh)"
|
||
|
||
set -euo pipefail
|
||
|
||
APP="authentik"
|
||
APP_DESCRIPTION="Authentik IdP (Docker-Compose) — Passkeys, TOTP, OIDC für nexus & Homelab"
|
||
APP_PORT="${APP_PORT:-9000}"
|
||
|
||
LIB_URL="${LIB_URL:-https://gitea.luki-net.org/luki-net/proxmox-scripts/raw/branch/main/lib}"
|
||
INSTALL_SCRIPT_URL="${INSTALL_SCRIPT_URL:-https://gitea.luki-net.org/luki-net/proxmox-scripts/raw/branch/main/install/authentik-install.sh}"
|
||
|
||
source <(curl -fsSL "$LIB_URL/build.func")
|
||
|
||
# LXC defaults (server+worker+postgres+redis brauchen Luft)
|
||
DEFAULT_HOSTNAME="authentik"
|
||
DEFAULT_DISK="20"
|
||
DEFAULT_CORES="2"
|
||
DEFAULT_RAM="4096"
|
||
|
||
prompt_app_config() {
|
||
echo
|
||
echo "── Authentik configuration ─────────────────────────────────"
|
||
if [[ -z "${AUTH_DOMAIN:-}" ]]; then
|
||
read -rp "Auth-Domain (dauerhaft! WebAuthn-RP-ID), z. B. auth.luki-net.org: " AUTH_DOMAIN
|
||
fi
|
||
[[ -n "${AUTH_DOMAIN:-}" ]] || { msg_err "AUTH_DOMAIN ist Pflicht"; exit 1; }
|
||
if [[ -z "${CLAUDE_SSH_PUBKEY:-}" ]]; then
|
||
read -rp "SSH-Public-Key für Agent-Zugang (leer = überspringen): " CLAUDE_SSH_PUBKEY || true
|
||
fi
|
||
# Authentik-Version: leer = Default des offiziellen Compose-Files
|
||
AUTHENTIK_TAG="${AUTHENTIK_TAG:-}"
|
||
echo " → domain: $AUTH_DOMAIN port: $APP_PORT tag: ${AUTHENTIK_TAG:-compose-default}"
|
||
}
|
||
|
||
push_app_config() {
|
||
msg_info "Pushing config into container..."
|
||
local tmpf; tmpf=$(mktemp)
|
||
cat >"$tmpf" <<EOF
|
||
AUTH_DOMAIN='$AUTH_DOMAIN'
|
||
APP_PORT='$APP_PORT'
|
||
AUTHENTIK_TAG='$AUTHENTIK_TAG'
|
||
CLAUDE_SSH_PUBKEY='${CLAUDE_SSH_PUBKEY:-}'
|
||
EOF
|
||
pct push "$CTID" "$tmpf" /root/authentik.deploy.env --perms 600
|
||
rm -f "$tmpf"
|
||
}
|
||
|
||
# Docker im unprivilegierten LXC braucht nesting+keyctl — vor dem Bootstrap setzen.
|
||
enable_nesting() {
|
||
msg_info "Enabling nesting+keyctl features (Docker in unprivileged LXC)..."
|
||
pct set "$CTID" --features nesting=1,keyctl=1
|
||
pct reboot "$CTID"
|
||
# warten bis der Container wieder antwortet
|
||
for _ in $(seq 1 30); do
|
||
pct exec "$CTID" -- true >/dev/null 2>&1 && break
|
||
sleep 2
|
||
done
|
||
msg_ok "Container restarted with nesting enabled"
|
||
}
|
||
|
||
print_app_summary() {
|
||
cat <<EOF
|
||
Authentik: http://$IP_CT:$APP_PORT (UI nach erstem Start, dauert 1–2 min)
|
||
Credentials/API-Token: /root/authentik.credentials (im LXC; akadmin + Bootstrap-Token)
|
||
Blueprints: /opt/authentik/blueprints (gemountet; Agent legt YAMLs ab,
|
||
Quelle versioniert in nexus-hub infra/authentik/)
|
||
|
||
⚠️ JETZT MANUELL (dauerhaft — WebAuthn-RP-ID):
|
||
NPMplus: Proxy Host $AUTH_DOMAIN → http://$IP_CT:$APP_PORT (WebSockets: ON)
|
||
|
||
Danach: Agent (Claude Code) per SSH übernimmt Blueprints/OIDC-Provider;
|
||
zuletzt Passkey-Enrollment des menschlichen Admin-Accounts über $AUTH_DOMAIN.
|
||
|
||
Logs: pct exec $CTID -- docker compose -f /opt/authentik/docker-compose.yml logs -f
|
||
EOF
|
||
}
|
||
|
||
trap _on_error ERR
|
||
preflight_pve
|
||
show_header "$APP" "$APP_DESCRIPTION"
|
||
prompt_lxc_config
|
||
prompt_app_config
|
||
resolve_debian_template
|
||
create_lxc
|
||
enable_nesting
|
||
push_app_config
|
||
bootstrap_install_script "$INSTALL_SCRIPT_URL"
|
||
print_summary
|