177 lines
6.8 KiB
Bash
Executable File
177 lines
6.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# run.sh — Start the FreeIPA stack with correct cgroup namespace on any host.
|
|
#
|
|
# Usage:
|
|
# ./run.sh # freeipa only
|
|
# ./run.sh all # whole stack (freeipa + postgres + keycloak + checkmk
|
|
# # + nextcloud + redis + nginx gateway)
|
|
# ./run.sh down # stop and remove containers
|
|
#
|
|
# Why this exists:
|
|
# The FreeIPA container runs systemd (/sbin/init) and requires the host cgroup
|
|
# namespace on systems that use cgroup v2 (WSL2, recent Fedora/Ubuntu, etc.).
|
|
# Docker Compose's schema does not expose a cgroupns_mode field, so this script
|
|
# starts the freeipa container via `docker run --cgroupns host` and defers the
|
|
# rest of the stack to `docker compose up`.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
[[ -f .env ]] || { echo "ERROR: .env not found. Copy .env.example and fill in values."; exit 1; }
|
|
# shellcheck disable=SC1091
|
|
source .env
|
|
|
|
MODE="${1:-}"
|
|
|
|
stop_freeipa() {
|
|
docker rm -f freeipa 2>/dev/null || true
|
|
}
|
|
|
|
# Create the nextcloud role/database if they are missing.
|
|
#
|
|
# postgres/initdb/10-nextcloud.sh already does this, but the image only runs
|
|
# initdb hooks when the data directory is empty. Stacks created before Nextcloud
|
|
# existed have a populated keycloak-db volume, so the hook never fires there and
|
|
# Nextcloud's installer would fail with "database nextcloud does not exist".
|
|
# This covers that upgrade path and is a no-op on fresh installs.
|
|
ensure_nextcloud_db() {
|
|
local _pw="${NC_DB_PASSWORD:?set NC_DB_PASSWORD in .env}"
|
|
|
|
echo "Waiting for PostgreSQL..."
|
|
local _i
|
|
for _i in $(seq 1 30); do
|
|
docker compose exec -T postgres pg_isready -U keycloak &>/dev/null && break
|
|
[[ $_i -eq 30 ]] && { echo "ERROR: PostgreSQL not ready after 60s."; exit 1; }
|
|
sleep 2
|
|
done
|
|
|
|
# psql has no CREATE ROLE/DATABASE IF NOT EXISTS, and CREATE DATABASE cannot
|
|
# run inside a transaction (so no DO block either) — hence query-then-create.
|
|
#
|
|
# The password is handed to psql as a variable and interpolated with :'pw',
|
|
# which applies psql's own literal quoting, so a password containing quotes
|
|
# or backslashes cannot break (or inject into) the statement.
|
|
#
|
|
# That interpolation only happens for SQL read from stdin — `psql -c` sends
|
|
# its argument to the server verbatim and would fail with a syntax error on
|
|
# the literal ":'pw'". Hence the inner heredoc rather than -c.
|
|
#
|
|
# The outer heredoc is quoted ('SH') so $NCPW expands in the container,
|
|
# where `docker compose exec -e` set it, and never on this host.
|
|
docker compose exec -T -e NCPW="$_pw" postgres sh -s <<'SH' \
|
|
&& echo "Nextcloud database ready." \
|
|
|| { echo "ERROR: could not create the nextcloud database."; exit 1; }
|
|
set -e
|
|
psql -U keycloak -d keycloak -tAc "SELECT 1 FROM pg_roles WHERE rolname='nextcloud'" \
|
|
| grep -q 1 \
|
|
|| psql -v ON_ERROR_STOP=1 -U keycloak -d keycloak -v pw="$NCPW" <<'Q'
|
|
CREATE ROLE nextcloud LOGIN PASSWORD :'pw';
|
|
Q
|
|
|
|
psql -U keycloak -d keycloak -tAc "SELECT 1 FROM pg_database WHERE datname='nextcloud'" \
|
|
| grep -q 1 \
|
|
|| psql -v ON_ERROR_STOP=1 -U keycloak -d keycloak <<'Q'
|
|
CREATE DATABASE nextcloud OWNER nextcloud ENCODING 'UTF8';
|
|
Q
|
|
SH
|
|
}
|
|
|
|
start_freeipa() {
|
|
stop_freeipa
|
|
|
|
# Ensure the compose-managed network exists before docker run uses it
|
|
docker compose up --no-start freeipa 2>/dev/null || true
|
|
NETWORK=$(docker network ls --filter name=ipa-net --format '{{.Name}}' | grep ipa-net | head -1)
|
|
if [[ -z "$NETWORK" ]]; then
|
|
# Label the network exactly as compose would so a later
|
|
# `docker compose up` (checkmk/postgres/keycloak) adopts it instead of
|
|
# failing with "network exists but was not created by compose".
|
|
docker network create --subnet=172.30.0.0/24 \
|
|
--label com.docker.compose.network=ipa-net \
|
|
--label com.docker.compose.project=image \
|
|
--label com.docker.compose.version=2 \
|
|
ipa-net
|
|
NETWORK=ipa-net
|
|
fi
|
|
|
|
# Ensure the data volumes exist (cmk-creds is shared with the checkmk
|
|
# container: CheckMK writes automation.secret there, the IPA container's
|
|
# ansipa-checkmk-setup.sh reads it — without this mount the whole
|
|
# dev_mon_* CheckMK integration silently never activates)
|
|
docker volume create freeipa-data 2>/dev/null || true
|
|
docker volume create cmk-creds 2>/dev/null || true
|
|
|
|
docker run -d \
|
|
--name freeipa \
|
|
--hostname "${IPA_HOSTNAME:-ipa.example.com}" \
|
|
--privileged \
|
|
--cgroupns host \
|
|
--tmpfs /run \
|
|
--tmpfs /tmp \
|
|
-v /sys/fs/cgroup:/sys/fs/cgroup:rw \
|
|
-v freeipa-data:/data \
|
|
-v cmk-creds:/cmk-creds \
|
|
--network "$NETWORK" \
|
|
--ip 172.30.0.10 \
|
|
-e IPA_DOMAIN="${IPA_DOMAIN:?}" \
|
|
-e IPA_REALM="${IPA_REALM:-}" \
|
|
-e IPA_ADMIN_PASSWORD="${IPA_ADMIN_PASSWORD:?}" \
|
|
-e IPA_DM_PASSWORD="${IPA_DM_PASSWORD:?}" \
|
|
-e IPA_SETUP_DNS="${IPA_SETUP_DNS:-false}" \
|
|
-e IPA_DNS_FORWARDER="${IPA_DNS_FORWARDER:-}" \
|
|
-e IPA_SETUP_KRA="${IPA_SETUP_KRA:-false}" \
|
|
-e LUKS_KEY_UPLOAD_PASSWORD="${LUKS_KEY_UPLOAD_PASSWORD:?}" \
|
|
-e CMK_URL="http://172.30.0.12:5000" \
|
|
-e CMK_ADVERTISED_URL="${CMK_ADVERTISED_URL:-}" \
|
|
-e CMK_SITE_ID="${CMK_SITE_ID:-cmk}" \
|
|
-e ANSIPA_GIT_SSH_PORT="${ANSIPA_GIT_SSH_PORT:-2222}" \
|
|
-e ANSIPA_GIT_ADMIN_PUBKEY="${ANSIPA_GIT_ADMIN_PUBKEY:-}" \
|
|
-e ANSIPA_GIT_SIGNING_PUBKEY="${ANSIPA_GIT_SIGNING_PUBKEY:-}" \
|
|
-p 389:389 \
|
|
-p 636:636 \
|
|
-p 88:88 \
|
|
-p 88:88/udp \
|
|
-p 464:464 \
|
|
-p 464:464/udp \
|
|
-p 443:443 \
|
|
-p 445:445 \
|
|
-p 139:139 \
|
|
-p 137:137/udp \
|
|
-p 138:138/udp \
|
|
-p "${ANSIPA_GIT_SSH_PORT:-2222}:${ANSIPA_GIT_SSH_PORT:-2222}" \
|
|
freeipa-server:local
|
|
|
|
echo "FreeIPA container started. Watch first-boot progress:"
|
|
echo " docker exec freeipa journalctl -f -u ipa-first-boot.service"
|
|
echo " (first-boot takes ~10 min)"
|
|
}
|
|
|
|
case "$MODE" in
|
|
down)
|
|
stop_freeipa
|
|
docker compose down
|
|
echo "Stack stopped."
|
|
;;
|
|
all)
|
|
start_freeipa
|
|
docker compose up -d postgres
|
|
ensure_nextcloud_db
|
|
docker compose up -d keycloak checkmk nextcloud-redis nextcloud nginx
|
|
echo "Full stack started (freeipa + postgres + keycloak + checkmk + nextcloud + nginx)."
|
|
echo
|
|
echo "Next, once the containers report healthy:"
|
|
echo " ./keycloak-configure.sh # Keycloak ← FreeIPA LDAP, and OIDC clients"
|
|
echo " ./nextcloud-configure.sh # Nextcloud ← IPA LDAP + Keycloak OIDC"
|
|
echo " ./checkmk-ldap-configure.sh # CheckMK ← FreeIPA LDAP"
|
|
;;
|
|
"")
|
|
start_freeipa
|
|
;;
|
|
*)
|
|
echo "Usage: $0 [all|down]"
|
|
exit 1
|
|
;;
|
|
esac
|