#!/usr/bin/env bash # ============================================================================= # ansipa-proxmox-lxc.sh — generate a pre-configured ansipa Proxmox LXC container # # Produces everything needed to stand up the FULL ansipa stack (FreeIPA + # CheckMK + Keycloak + PostgreSQL + nginx gateway) inside a single Proxmox LXC # container, using the tested docker-compose deployment run inside the CT # ("Docker-in-LXC"). This is the whole management plane in one container, unlike # freeipa-image.sh's proxmox-lxc target which exports a FreeIPA-only rootfs. # # Why Docker-in-LXC instead of native install: # FreeIPA + CheckMK + Keycloak are already packaged and wired together as a # compose stack that this repo tests end-to-end. Running that stack inside a # privileged, nesting-enabled LXC reuses all of it verbatim and keeps the # Proxmox container reproducible. # # OUTPUT (written to an output dir, default ~/ansipa-lxc-out): # pct-create-.sh runnable pct create command (run on the Proxmox host) # ansipa-.conf LXC options to append to /etc/pve/lxc/.conf # ansipa-provision.sh first-boot provisioner (installs Docker + brings the # stack up); copied into the CT and run once # .env filled-in ansipa stack environment (secrets!) # DEPLOY-.md step-by-step deployment guide # # Requirements on the workstation running THIS script: bash, openssl (for # password generation). The Proxmox host needs a Debian 12 CT template. # ============================================================================= set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DOTFILES_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" IMAGE_SRC="$DOTFILES_DIR/setup/modules/FreeipaAnsible/image" RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' BLUE='\033[0;34m'; CYAN='\033[0;36m'; MAGENTA='\033[0;35m'; NC='\033[0m' log() { echo -e "${GREEN}[+]${NC} $*"; } warn() { echo -e "${YELLOW}[!]${NC} $*"; } error() { echo -e "${RED}[✗]${NC} $*" >&2; } info() { echo -e "${CYAN}[i]${NC} $*"; } section() { echo -e "\n${BLUE}━━━ $* ━━━${NC}"; } ask() { printf "${MAGENTA}[?]${NC} %s " "$*"; } [[ $EUID -eq 0 ]] && { error "Run as your normal user (not root)."; exit 1; } gen_pw() { openssl rand -base64 18 2>/dev/null | tr -d '/+=' | cut -c1-20; } # ─── Gather configuration ───────────────────────────────────────────────────── section "ansipa Proxmox LXC generator" info "Generates a pre-configured full-stack ansipa container for Proxmox." echo ask "IPA domain (e.g. corp.example.com):"; read -r IPA_DOMAIN [[ -z "$IPA_DOMAIN" ]] && { error "IPA domain is required."; exit 1; } ask "IPA server FQDN [ipa.$IPA_DOMAIN]:"; read -r I; IPA_HOSTNAME="${I:-ipa.$IPA_DOMAIN}" ask "Kerberos realm [${IPA_DOMAIN^^}]:"; read -r I; IPA_REALM="${I:-${IPA_DOMAIN^^}}" ask "Proxmox VMID [910]:"; read -r I; VMID="${I:-910}" ask "CT hostname [ansipa]:"; read -r I; CT_HOSTNAME="${I:-ansipa}" ask "Proxmox storage [local-lvm]:"; read -r I; PVE_STORAGE="${I:-local-lvm}" ask "Template storage [local]:"; read -r I; TPL_STORAGE="${I:-local}" ask "Debian CT template [debian-12-standard_12.7-1_amd64.tar.zst]:"; read -r I CT_TEMPLATE="${I:-debian-12-standard_12.7-1_amd64.tar.zst}" # FreeIPA alone wants ~2 GB; the full stack (CheckMK/Keycloak/Postgres) needs headroom. ask "RAM MB [6144]:"; read -r I; CT_RAM="${I:-6144}" ask "Cores [4]:"; read -r I; CT_CORES="${I:-4}" ask "Disk GB [20]:"; read -r I; CT_DISK="${I:-20}" ask "Bridge [vmbr0]:"; read -r I; CT_BRIDGE="${I:-vmbr0}" ask "Static IP CIDR or 'dhcp' [dhcp]:"; read -r I; CT_IP="${I:-dhcp}" ask "Advertised CheckMK URL for clients (e.g. http://ansipa.$IPA_DOMAIN:8090) [blank=set later]:" read -r CMK_ADVERTISED_URL OUT_DIR="${1:-$HOME/ansipa-lxc-out}" mkdir -p "$OUT_DIR" # ─── Generate secrets ───────────────────────────────────────────────────────── section "Generating secrets" IPA_ADMIN_PASSWORD=$(gen_pw); IPA_DM_PASSWORD=$(gen_pw) CMK_ADMIN_PASSWORD=$(gen_pw); KC_ADMIN_PASSWORD=$(gen_pw); KC_DB_PASSWORD=$(gen_pw) LUKS_KEY_UPLOAD_PASSWORD=$(gen_pw) log "Generated admin/service passwords (saved in $OUT_DIR/.env — keep it safe)." # ─── .env for the ansipa stack ──────────────────────────────────────────────── cat > "$OUT_DIR/.env" < "$OUT_DIR/pct-create-$VMID.sh" <> /etc/pve/lxc/$VMID.conf" echo " pct start $VMID" echo " pct push $VMID ansipa-provision.sh /root/ansipa-provision.sh" echo " pct push $VMID .env /root/.env" echo " pct exec $VMID -- bash /root/ansipa-provision.sh" EOF chmod +x "$OUT_DIR/pct-create-$VMID.sh" # ─── LXC config extras ──────────────────────────────────────────────────────── # Docker overlay2 + FreeIPA need these cgroup/device allowances in a CT. cat > "$OUT_DIR/ansipa-$VMID.conf" < "$OUT_DIR/ansipa-provision.sh" <<'PROVEOF' #!/usr/bin/env bash # ansipa-provision.sh — runs once inside the LXC to bring up the ansipa stack. set -euo pipefail export DEBIAN_FRONTEND=noninteractive echo "[ansipa] Installing Docker + git..." apt-get update -qq apt-get install -y -qq ca-certificates curl git >/dev/null install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release; echo $VERSION_CODENAME) stable" \ > /etc/apt/sources.list.d/docker.list apt-get update -qq apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null systemctl enable --now docker echo "[ansipa] Fetching the ansipa stack..." git clone --depth 1 https://git.abdelbaki.eu/The_miro/Dotfiles.git /opt/ansipa-src 2>/dev/null \ || { cd /opt/ansipa-src && git pull; } STACK=/opt/ansipa mkdir -p "$STACK" cp -r /opt/ansipa-src/setup/modules/FreeipaAnsible/image/. "$STACK/" cp /root/.env "$STACK/.env" echo "[ansipa] Starting the full stack (this builds the FreeIPA image + first-boot ~10 min)..." cd "$STACK" # cgroup v2 hosts need run.sh (compose can't express --cgroupns host for FreeIPA). if [ "$(stat -fc %T /sys/fs/cgroup 2>/dev/null)" = "cgroup2fs" ]; then bash ./run.sh all else docker compose up -d fi echo "[ansipa] Stack starting. Watch first-boot with:" echo " docker logs -f freeipa" echo "[ansipa] Once healthy, wire Keycloak↔FreeIPA LDAP: cd $STACK && ./keycloak-configure.sh" PROVEOF chmod +x "$OUT_DIR/ansipa-provision.sh" # ─── Deployment guide ───────────────────────────────────────────────────────── cat > "$OUT_DIR/DEPLOY-$VMID.md" <> /etc/pve/lxc/$VMID.conf pct start $VMID pct push $VMID .env /root/.env pct push $VMID ansipa-provision.sh /root/ansipa-provision.sh pct exec $VMID -- bash /root/ansipa-provision.sh \`\`\` ## 3. Access - Portal / all UIs: \`http://:8088/\` (put your reverse proxy in front — see docs/md/ansipa-setup.md) - FreeIPA: \`/ipa/ui/\` · CheckMK: \`/cmk/\` · Keycloak: \`/auth/\` - Admin passwords are in \`.env\` (IPA_ADMIN_PASSWORD, CMK_ADMIN_PASSWORD, KC_ADMIN_PASSWORD). ## Notes - The CT is **privileged** with nesting/keyctl/fuse — required for FreeIPA's systemd + Kerberos keyrings and Docker's overlay2. Do not run untrusted workloads in it. - RAM: ${CT_RAM} MB. FreeIPA + CheckMK + Keycloak together need ~4–6 GB. - Firewall: open the ansipa ports (see docs/md/ansipa-setup.md → Ports). EOF # ─── Summary ────────────────────────────────────────────────────────────────── section "Done" log "Artifacts written to: $OUT_DIR" info " pct-create-$VMID.sh — create the CT (run on Proxmox host)" info " ansipa-$VMID.conf — append to /etc/pve/lxc/$VMID.conf" info " ansipa-provision.sh — first-boot provisioner (run inside CT)" info " .env — stack secrets (mode 600 — keep safe)" info " DEPLOY-$VMID.md — full deployment guide" echo warn "The .env contains generated admin passwords in plain text. Store it securely."