e77a963390
ci / changes (push) Successful in 3s
ci / tc_portal (push) Has been skipped
ci / tc_booking (push) Has been skipped
ci / tc_operator (push) Has been skipped
ci / tc_platform_api (push) Has been skipped
ci / tc_website (push) Has been skipped
ci / build_portal (push) Has been skipped
ci / test_platform_api (push) Has been skipped
ci / build_booking (push) Has been skipped
ci / build_operator (push) Has been skipped
ci / build_platform_api (push) Has been skipped
ci / deploy (push) Has been skipped
The cert-sync timer waited forever for a mail/mail-tls secret no
Certificate resource ever requested — Stalwart served self-signed certs
since install, so mail clients refused the IMAP handshake ('cannot verify
account name or password' in Apple Mail). Adds the cert-manager
Certificate (HTTP-01 via Traefik on :80) and documents the v0.16 wrinkle:
TLS files aren't read from config anymore; a one-time file-backed
x:Certificate object (created via management JMAP) points at the synced
paths, after which cert-sync renewals keep working unchanged. Verified:
:993 now serves the Let's Encrypt cert, verify rc=0.
86 lines
3.4 KiB
Bash
Executable File
86 lines
3.4 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.
|
|
#
|
|
# v0.16 NOTE: Stalwart no longer reads TLS files directly from config.toml.
|
|
# A one-time x:Certificate object (management JMAP) points at these paths
|
|
# with the File variant:
|
|
# {"certificate":{"@type":"File","filePath":"/opt/stalwart/etc/tls/cert.pem"},
|
|
# "privateKey":{"@type":"File","filePath":"/opt/stalwart/etc/tls/key.pem"}}
|
|
# Created 2026-06-10. With that in place this script's file update + reload
|
|
# keeps working for renewals exactly as designed.
|
|
#
|
|
# 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
|