241 lines
11 KiB
Bash
Executable File
241 lines
11 KiB
Bash
Executable File
#!/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-<vmid>.sh runnable pct create command (run on the Proxmox host)
|
||
# ansipa-<vmid>.conf LXC options to append to /etc/pve/lxc/<vmid>.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-<vmid>.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" <<EOF
|
||
# ansipa stack environment — generated by ansipa-proxmox-lxc.sh
|
||
IPA_HOSTNAME=$IPA_HOSTNAME
|
||
IPA_DOMAIN=$IPA_DOMAIN
|
||
IPA_REALM=$IPA_REALM
|
||
IPA_ADMIN_PASSWORD=$IPA_ADMIN_PASSWORD
|
||
IPA_DM_PASSWORD=$IPA_DM_PASSWORD
|
||
IPA_SETUP_DNS=false
|
||
IPA_SETUP_KRA=false
|
||
|
||
LUKS_KEY_UPLOAD_PASSWORD=$LUKS_KEY_UPLOAD_PASSWORD
|
||
|
||
CMK_ADMIN_PASSWORD=$CMK_ADMIN_PASSWORD
|
||
CMK_SITE_ID=cmk
|
||
CMK_ADVERTISED_URL=$CMK_ADVERTISED_URL
|
||
|
||
KC_HOSTNAME=${IPA_HOSTNAME/ipa./sso.}
|
||
KC_ADMIN=admin
|
||
KC_ADMIN_PASSWORD=$KC_ADMIN_PASSWORD
|
||
KC_DB_PASSWORD=$KC_DB_PASSWORD
|
||
|
||
ANSIPA_HTTP_PORT=8088
|
||
EOF
|
||
chmod 600 "$OUT_DIR/.env"
|
||
|
||
# ─── pct create script ────────────────────────────────────────────────────────
|
||
# Privileged + nesting + keyctl + fuse: FreeIPA runs systemd and Docker needs
|
||
# nesting/overlay; keyctl is required by Kerberos/SSSD keyrings inside the CT.
|
||
NET_LINE="name=eth0,bridge=$CT_BRIDGE,ip=dhcp"
|
||
[[ "$CT_IP" != "dhcp" ]] && NET_LINE="name=eth0,bridge=$CT_BRIDGE,ip=$CT_IP"
|
||
|
||
cat > "$OUT_DIR/pct-create-$VMID.sh" <<EOF
|
||
#!/usr/bin/env bash
|
||
# Run on the Proxmox host. Creates the ansipa LXC container.
|
||
set -euo pipefail
|
||
|
||
pct create $VMID $TPL_STORAGE:vztmpl/$CT_TEMPLATE \\
|
||
--hostname $CT_HOSTNAME \\
|
||
--cores $CT_CORES \\
|
||
--memory $CT_RAM \\
|
||
--swap 2048 \\
|
||
--rootfs $PVE_STORAGE:$CT_DISK \\
|
||
--net0 $NET_LINE \\
|
||
--features nesting=1,keyctl=1,fuse=1 \\
|
||
--unprivileged 0 \\
|
||
--onboot 1 \\
|
||
--start 0
|
||
|
||
echo "Created CT $VMID. Now append the extra options and start it:"
|
||
echo " cat ansipa-$VMID.conf >> /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" <<EOF
|
||
# Append to /etc/pve/lxc/$VMID.conf — enables Docker + FreeIPA inside the CT.
|
||
lxc.apparmor.profile: unconfined
|
||
lxc.cgroup2.devices.allow: a
|
||
lxc.cap.drop:
|
||
lxc.mount.auto: proc:rw sys:rw
|
||
EOF
|
||
|
||
# ─── First-boot provisioner (runs INSIDE the container) ───────────────────────
|
||
cat > "$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" <<EOF
|
||
# ansipa Proxmox LXC — deployment ($CT_HOSTNAME, VMID $VMID)
|
||
|
||
Generated by \`ansipa-proxmox-lxc.sh\`. Runs the full ansipa stack
|
||
(FreeIPA + CheckMK + Keycloak + PostgreSQL + nginx) as Docker containers
|
||
inside a privileged, nesting-enabled Proxmox LXC.
|
||
|
||
## 1. Copy these files to the Proxmox host
|
||
\`\`\`
|
||
scp pct-create-$VMID.sh ansipa-$VMID.conf ansipa-provision.sh .env root@PROXMOX:/root/ansipa/
|
||
\`\`\`
|
||
|
||
## 2. Create and provision the container (on the Proxmox host)
|
||
\`\`\`
|
||
cd /root/ansipa
|
||
# Ensure the Debian template exists: pveam update && pveam download $TPL_STORAGE $CT_TEMPLATE
|
||
bash pct-create-$VMID.sh
|
||
cat ansipa-$VMID.conf >> /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://<CT-IP>: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."
|