Files
edgeguard-native/packaging/debian/edgeguard-api/DEBIAN/postinst
Debian a0ab929b9a fix(postinst): nftables auch beim Upgrade reloaden
Vorher: render-config --no-reload schrieb nur die Files; haproxy
wurde explizit per systemctl restart unten neu gefahren, aber
nft-Set blieb beim Kernel-Stand vom letzten Boot. Bug sichtbar bei
1.0.13: Anti-Lockout-Eintrag für 3443 war im Template, aber der
Kernel hatte die Regel nicht — Port von außen blockiert.

Fix: zwei render-Calls — haproxy mit --no-reload (wie bisher),
nftables ohne, damit `sudo nft -f` direkt nach dem Schreiben
ausgeführt wird.

Version 1.0.14.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 21:41:54 +02:00

143 lines
6.7 KiB
Bash
Executable File

#!/bin/bash
# postinst for edgeguard-api — creates system user, filesystem layout,
# initialises PostgreSQL (role + db + migrations), enables systemd
# units. Each step idempotent; safe to re-run on every upgrade.
set -e
export LC_ALL=C
export LANG=C
EG_USER="edgeguard"
EG_HOME="/var/lib/edgeguard"
case "$1" in
configure)
# ── System user ──────────────────────────────────────────────
if ! getent passwd "$EG_USER" >/dev/null; then
adduser --system --group --home "$EG_HOME" \
--shell /usr/sbin/nologin --no-create-home \
--gecos "EdgeGuard daemon" "$EG_USER"
fi
# ── Directories ──────────────────────────────────────────────
for d in /etc/edgeguard /var/lib/edgeguard /var/log/edgeguard \
/etc/edgeguard/haproxy /etc/edgeguard/squid \
/etc/edgeguard/wireguard /etc/edgeguard/unbound \
/etc/edgeguard/nftables.d /etc/edgeguard/tls \
/var/lib/edgeguard/acme; do
install -d -m 0750 -o "$EG_USER" -g "$EG_USER" "$d"
done
# ACME-Account-Dir 0700 — hält den lego-Account-Schlüssel,
# gehört nur edgeguard.
install -d -m 0700 -o "$EG_USER" -g "$EG_USER" /var/lib/edgeguard/acme-account
# ── sudoers: HAProxy reload + (later) systemd-networkd reload
# Damit edgeguard-api nach einer SSL- oder Netzwerk-Mutation
# selbst reloaden kann ohne root zu sein. NOPASSWD ist auf
# genau dieses Kommando beschränkt.
cat > /etc/sudoers.d/edgeguard <<'SUDOERS'
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl reload haproxy.service
edgeguard ALL=(root) NOPASSWD: /bin/systemctl reload haproxy.service
edgeguard ALL=(root) NOPASSWD: /usr/sbin/nft -f /etc/edgeguard/nftables.d/ruleset.nft
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl start wg-quick@*.service
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl restart wg-quick@*.service
edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl stop wg-quick@*.service
edgeguard ALL=(root) NOPASSWD: /bin/systemctl start wg-quick@*.service
edgeguard ALL=(root) NOPASSWD: /bin/systemctl restart wg-quick@*.service
edgeguard ALL=(root) NOPASSWD: /bin/systemctl stop wg-quick@*.service
edgeguard ALL=(root) NOPASSWD: /usr/bin/wg show all dump
edgeguard ALL=(root) NOPASSWD: /usr/bin/wg show *
SUDOERS
chmod 0440 /etc/sudoers.d/edgeguard
# ── Self-signed default cert so HAProxy starts cleanly ───────
# HAProxy `bind :443 ssl crt /etc/edgeguard/tls/` needs at least
# one PEM in the directory to come up. Operator runs certbot
# later; until then, browsers see an unverified cert which is
# the expected first-boot UX.
DEFAULT_PEM="/etc/edgeguard/tls/_default.pem"
if [ ! -f "$DEFAULT_PEM" ]; then
HOSTNAME_FQDN="$(hostname -f 2>/dev/null || hostname)"
TMP_KEY="$(mktemp)"
TMP_CRT="$(mktemp)"
openssl req -x509 -nodes -newkey rsa:2048 \
-keyout "$TMP_KEY" -out "$TMP_CRT" \
-days 3650 \
-subj "/CN=$HOSTNAME_FQDN" \
-addext "subjectAltName = DNS:$HOSTNAME_FQDN,DNS:localhost" \
>/dev/null 2>&1
cat "$TMP_CRT" "$TMP_KEY" > "$DEFAULT_PEM"
chown "$EG_USER:$EG_USER" "$DEFAULT_PEM"
chmod 0640 "$DEFAULT_PEM"
rm -f "$TMP_KEY" "$TMP_CRT"
fi
# ── Pre-flight: validate embedded migration set ──────────────
# Catches duplicate version prefixes BEFORE we touch the DB,
# so a broken upgrade can't half-apply migrations and leave
# the cluster wedged (mail-gateway 2026-05-08 incident).
if ! /usr/bin/edgeguard-ctl migrate check; then
echo "postinst: embedded migrations failed validation — aborting" >&2
exit 1
fi
# ── PostgreSQL: ensure role + database exist ─────────────────
# Requires postgresql-16 (or -17) running locally — guaranteed
# by Depends. Idempotent — re-runs on upgrade are no-ops.
if ! /usr/bin/edgeguard-ctl initdb; then
echo "postinst: edgeguard-ctl initdb failed — aborting" >&2
exit 1
fi
# ── Apply pending schema migrations ──────────────────────────
if ! sudo -n -u "$EG_USER" /usr/bin/edgeguard-ctl migrate up; then
echo "postinst: edgeguard-ctl migrate up failed — aborting" >&2
exit 1
fi
# ── Render initial service configs ───────────────────────────
# Writes /etc/edgeguard/haproxy/haproxy.cfg + nftables.d/
# ruleset.nft from the (just-migrated, empty) PG state.
#
# haproxy bekommt --no-reload (drop-in unten zeigt erst danach
# auf unsere cfg; wir restarten explizit); nftables muss aber
# aktiv reloadet werden, sonst läuft das Kernel-Set bei Template-
# Änderungen (z.B. neue anti-lockout-Ports) hinterher.
if ! sudo -n -u "$EG_USER" /usr/bin/edgeguard-ctl render-config --only=haproxy --no-reload; then
echo "postinst: edgeguard-ctl render-config (haproxy) failed — aborting" >&2
exit 1
fi
if ! sudo -n -u "$EG_USER" /usr/bin/edgeguard-ctl render-config --only=nftables; then
echo "postinst: edgeguard-ctl render-config (nftables) failed — aborting" >&2
exit 1
fi
# ── HAProxy systemd drop-in: read EdgeGuard config ───────────
# Keeps the distro /etc/haproxy/haproxy.cfg untouched (it's a
# conffile of the haproxy package). Drop-in is reversible by
# removing the file + daemon-reload.
install -d /etc/systemd/system/haproxy.service.d
if [ -f /etc/edgeguard/systemd/haproxy-edgeguard.conf ]; then
install -m 0644 /etc/edgeguard/systemd/haproxy-edgeguard.conf \
/etc/systemd/system/haproxy.service.d/edgeguard.conf
fi
# ── systemd: pick up new units + restart haproxy with our cfg
systemctl daemon-reload
systemctl restart haproxy.service || true
systemctl enable --now edgeguard-api.service edgeguard-scheduler.service || true
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
#DEBHELPER#
exit 0