3831c85285
Host provisioning for the single-server production target: SSH + firewall hardening (nftables allowlist), k3s node registration, bare-metal Stalwart install with systemd units and TLS cert-sync from the cluster secret, and Restic encrypted backup/restore (primary + DR) with timer units. Host-specific secrets live in config.env (gitignored); config.env.example is the template. Also gitignores MemPalace per-project files.
78 lines
2.9 KiB
Bash
Executable File
78 lines
2.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Sync the mail.dezky.eu TLS cert from the cluster (issued by cert-manager) to
|
|
# Stalwart on the host. The host IS the k3s node, so we read the secret via the
|
|
# local kubeconfig — no external machinery. Reloads Stalwart only when the cert
|
|
# actually changed (cert-manager renews ~30 days before expiry).
|
|
#
|
|
# Run by stalwart-cert-sync.timer (every 12h + on boot). Safe to run by hand.
|
|
#
|
|
# Forward dependency: needs the fleet layer to have created the TLS secret
|
|
# (default: namespace 'mail', secret 'mail-tls'). Until then this is a no-op and
|
|
# Stalwart keeps using the self-signed bootstrap cert from install.sh.
|
|
|
|
set -euo pipefail
|
|
|
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
|
|
info() { echo -e "${BLUE}[INFO]${NC} $*"; }
|
|
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
|
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
|
|
|
TLS_NAMESPACE="${TLS_NAMESPACE:-mail}"
|
|
TLS_SECRET="${TLS_SECRET:-mail-tls}"
|
|
TLS_DIR="/opt/stalwart/etc/tls"
|
|
KUBECONFIG_PATH="${KUBECONFIG:-/etc/rancher/k3s/k3s.yaml}"
|
|
|
|
# kubectl: prefer standalone, fall back to the k3s-bundled one
|
|
if command -v kubectl >/dev/null 2>&1; then
|
|
KUBECTL=(kubectl)
|
|
elif command -v k3s >/dev/null 2>&1; then
|
|
KUBECTL=(k3s kubectl)
|
|
else
|
|
error "Neither kubectl nor k3s found — is the node provisioned yet?"
|
|
exit 1
|
|
fi
|
|
export KUBECONFIG="$KUBECONFIG_PATH"
|
|
|
|
# Pull the secret (no-op if it doesn't exist yet)
|
|
if ! "${KUBECTL[@]}" -n "$TLS_NAMESPACE" get secret "$TLS_SECRET" >/dev/null 2>&1; then
|
|
warn "Secret ${TLS_NAMESPACE}/${TLS_SECRET} not present yet — cert-manager hasn't issued it. Skipping."
|
|
exit 0
|
|
fi
|
|
|
|
TMP_CRT="$(mktemp)"; TMP_KEY="$(mktemp)"
|
|
trap 'rm -f "$TMP_CRT" "$TMP_KEY"' EXIT
|
|
|
|
"${KUBECTL[@]}" -n "$TLS_NAMESPACE" get secret "$TLS_SECRET" \
|
|
-o jsonpath='{.data.tls\.crt}' | base64 -d > "$TMP_CRT"
|
|
"${KUBECTL[@]}" -n "$TLS_NAMESPACE" get secret "$TLS_SECRET" \
|
|
-o jsonpath='{.data.tls\.key}' | base64 -d > "$TMP_KEY"
|
|
|
|
if [[ ! -s "$TMP_CRT" || ! -s "$TMP_KEY" ]]; then
|
|
error "Fetched cert or key is empty — leaving current cert in place."
|
|
exit 1
|
|
fi
|
|
|
|
# Only reload if something changed (compare hashes)
|
|
changed=0
|
|
mkdir -p "$TLS_DIR"
|
|
if ! cmp -s "$TMP_CRT" "$TLS_DIR/cert.pem" 2>/dev/null; then changed=1; fi
|
|
if ! cmp -s "$TMP_KEY" "$TLS_DIR/key.pem" 2>/dev/null; then changed=1; fi
|
|
|
|
if [[ $changed -eq 0 ]]; then
|
|
info "Cert unchanged — nothing to do."
|
|
exit 0
|
|
fi
|
|
|
|
install -o stalwart -g stalwart -m 0644 "$TMP_CRT" "$TLS_DIR/cert.pem"
|
|
install -o stalwart -g stalwart -m 0640 "$TMP_KEY" "$TLS_DIR/key.pem"
|
|
ok "Updated mail TLS cert from ${TLS_NAMESPACE}/${TLS_SECRET}."
|
|
|
|
# SIGHUP Stalwart to reload certs without dropping connections
|
|
if systemctl is-active --quiet stalwart-mail; then
|
|
systemctl reload stalwart-mail && ok "Reloaded stalwart-mail (SIGHUP)."
|
|
else
|
|
warn "stalwart-mail not active — cert staged, will be used on next start."
|
|
fi
|