email-amazon/DMS/setup-dms-tls.sh

207 lines
6.8 KiB
Bash
Executable File

#!/bin/bash
# setup-dms-tls.sh
# Gehört ins Root-Verzeichnis des DMS (neben docker-compose.yml).
#
# Generiert Dovecot- und Postfix-SNI-Konfigurationen für Multi-Domain TLS.
# Liest Domains aus dem laufenden DMS und erstellt:
# - docker-data/dms/config/dovecot-sni.cf
# - docker-data/dms/config/postfix-main.cf
# - docker-data/dms/config/postfix-sni.map (NEU für Postfix SNI)
#
# Cert-Konvention (Caddy Wildcard):
# Caddy speichert *.domain.tld unter: wildcard_.domain.tld/wildcard_.domain.tld.crt
# Im Container (gemountet unter /etc/mail/certs):
# /etc/mail/certs/wildcard_.domain.tld/wildcard_.domain.tld.crt
# /etc/mail/certs/wildcard_.domain.tld/wildcard_.domain.tld.key
#
# Usage:
# ./setup-dms-tls.sh
# DMS_CONTAINER=mailserver NODE_HOSTNAME=node1.email-srvr.com ./setup-dms-tls.sh
set -e
DMS_CONTAINER=${DMS_CONTAINER:-"mailserver"}
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
CONFIG_DIR="$SCRIPT_DIR/docker-data/dms/config"
CERTS_BASE_PATH=${CERTS_BASE_PATH:-"/etc/mail/certs"}
# Node-Hostname: Fallback-Cert für DMS (kein Wildcard, direktes Cert)
# Muss mit dem 'hostname' in docker-compose.yml übereinstimmen.
NODE_HOSTNAME=${NODE_HOSTNAME:-"node1.email-srvr.com"}
echo "============================================================"
echo " 🔐 DMS TLS SNI Setup (Multi-Domain)"
echo " DMS Container: $DMS_CONTAINER"
echo " Config Dir: $CONFIG_DIR"
echo " Certs Base: $CERTS_BASE_PATH"
echo " Node Hostname: $NODE_HOSTNAME"
echo "============================================================"
# --- Domains aus DMS lesen ---
echo ""
echo "📋 Lese Domains aus DMS..."
DOMAINS=$(docker exec "$DMS_CONTAINER" setup email list 2>/dev/null \
| grep -oP '(?<=@)[^\s]+' \
| sort -u)
if [ -z "$DOMAINS" ]; then
echo "❌ Keine Accounts im DMS gefunden!"
echo " Bitte zuerst anlegen: ./manage_mail_user.sh add user@domain.com PW"
exit 1
fi
echo " Gefundene Domains:"
for d in $DOMAINS; do echo " - $d"; done
# --- Cert-Pfad Hilfsfunktionen ---
wildcard_cert_path() {
echo "$CERTS_BASE_PATH/wildcard_.${1}/wildcard_.${1}.crt"
}
wildcard_key_path() {
echo "$CERTS_BASE_PATH/wildcard_.${1}/wildcard_.${1}.key"
}
# --- Cert-Verfügbarkeit im Container prüfen ---
echo ""
echo "🔍 Prüfe Zertifikat-Verfügbarkeit..."
DOMAINS_OK=""
DOMAINS_MISSING=""
for domain in $DOMAINS; do
CERT_PATH=$(wildcard_cert_path "$domain")
KEY_PATH=$(wildcard_key_path "$domain")
if docker exec "$DMS_CONTAINER" test -f "$CERT_PATH" 2>/dev/null; then
echo "$domain$CERT_PATH"
DOMAINS_OK="$DOMAINS_OK $domain"
else
echo " ⚠️ $domain → KEIN Cert unter $CERT_PATH"
echo " → update-caddy-certs.sh ausführen + caddy reload!"
DOMAINS_MISSING="$DOMAINS_MISSING $domain"
fi
done
# Node-Hostname Cert prüfen (direktes Cert, kein Wildcard)
NODE_CERT_PATH="$CERTS_BASE_PATH/$NODE_HOSTNAME/$NODE_HOSTNAME.crt"
NODE_KEY_PATH="$CERTS_BASE_PATH/$NODE_HOSTNAME/$NODE_HOSTNAME.key"
if docker exec "$DMS_CONTAINER" test -f "$NODE_CERT_PATH" 2>/dev/null; then
echo "$NODE_HOSTNAME → Cert vorhanden (Node Default)"
else
echo " ⚠️ $NODE_HOSTNAME → KEIN Cert! Caddy-Block im Caddyfile prüfen."
fi
if [ -n "$DOMAINS_MISSING" ]; then
echo ""
echo " ⚠️ Fehlende Certs:$DOMAINS_MISSING"
echo " Diese Domains werden NICHT in SNI-Config eingetragen."
fi
if [ -z "$DOMAINS_OK" ]; then
echo "❌ Kein einziges Kundendomain-Cert gefunden!"
echo " Bitte zuerst update-caddy-certs.sh ausführen + caddy reload abwarten."
exit 1
fi
# ================================================================
# DOVECOT SNI Konfiguration
# ================================================================
DOVECOT_CFG="$CONFIG_DIR/dovecot-sni.cf"
echo ""
echo "📝 Generiere: $DOVECOT_CFG"
cat > "$DOVECOT_CFG" << 'HEADER'
# dovecot-sni.cf - Automatisch generiert von setup-dms-tls.sh
# SNI-basierte Zertifikat-Auswahl für Dovecot (IMAP/POP3).
# Dovecot liest dieses File über den Volume-Mount in /tmp/docker-mailserver/
# und wendet es automatisch an.
HEADER
for domain in $DOMAINS_OK; do
CERT_PATH=$(wildcard_cert_path "$domain")
KEY_PATH=$(wildcard_key_path "$domain")
cat >> "$DOVECOT_CFG" << EOF
# $domain
local_name mail.$domain {
ssl_cert = <$CERT_PATH
ssl_key = <$KEY_PATH
}
local_name imap.$domain {
ssl_cert = <$CERT_PATH
ssl_key = <$KEY_PATH
}
local_name smtp.$domain {
ssl_cert = <$CERT_PATH
ssl_key = <$KEY_PATH
}
local_name pop.$domain {
ssl_cert = <$CERT_PATH
ssl_key = <$KEY_PATH
}
EOF
done
echo " ✅ Dovecot SNI: $(echo $DOMAINS_OK | wc -w) Domain(s)"
# ================================================================
# POSTFIX SNI Konfiguration (Neu geschrieben für echte SNI Maps)
# ================================================================
POSTFIX_CFG="$CONFIG_DIR/postfix-main.cf"
POSTFIX_MAP="$CONFIG_DIR/postfix-sni.map"
echo ""
echo "📝 Generiere: $POSTFIX_CFG und $POSTFIX_MAP"
if [ -f "$POSTFIX_CFG" ]; then
cp "$POSTFIX_CFG" "${POSTFIX_CFG}.bak.$(date +%Y%m%d%H%M%S)"
fi
# 1. postfix-main.cf erstellen
cat > "$POSTFIX_CFG" << POSTFIX_EOF
# postfix-main.cf - Automatisch generiert von setup-dms-tls.sh
#
# 1. Fallback-Zertifikat (Wird genutzt, wenn kein SNI-Match gefunden wird)
smtpd_tls_chain_files = ${NODE_KEY_PATH}, ${NODE_CERT_PATH}
# 2. SNI-Mapping aktivieren
# Wir nutzen 'texthash', damit Postfix die Map direkt lesen kann,
# ohne dass 'postmap' ausgeführt werden muss!
tls_server_sni_maps = texthash:/tmp/docker-mailserver/postfix-sni.map
POSTFIX_EOF
# 2. postfix-sni.map erstellen
echo "# postfix-sni.map - Automatisch generiert (Format: host key_pfad cert_pfad)" > "$POSTFIX_MAP"
for domain in $DOMAINS_OK; do
KEY_PATH=$(wildcard_key_path "$domain")
CERT_PATH=$(wildcard_cert_path "$domain")
cat >> "$POSTFIX_MAP" << EOF
mail.${domain} ${KEY_PATH} ${CERT_PATH}
smtp.${domain} ${KEY_PATH} ${CERT_PATH}
imap.${domain} ${KEY_PATH} ${CERT_PATH}
pop.${domain} ${KEY_PATH} ${CERT_PATH}
${domain} ${KEY_PATH} ${CERT_PATH}
EOF
done
echo " ✅ Postfix SNI: $(echo $DOMAINS_OK | wc -w) Domain(s) konfiguriert"
# ================================================================
# Zusammenfassung
# ================================================================
echo ""
echo "============================================================"
echo "✅ Konfigurationen generiert."
echo ""
echo "🔄 Lade Postfix und Dovecot neu (ohne Downtime)..."
docker exec "$DMS_CONTAINER" postfix reload || echo "⚠️ Postfix Reload fehlgeschlagen"
docker exec "$DMS_CONTAINER" dovecot reload || echo "⚠️ Dovecot Reload fehlgeschlagen"
echo ""
echo "📋 Nächste Schritte:"
echo ""
echo "1. TLS testen (SNI):"
for domain in $DOMAINS_OK; do
echo " openssl s_client -connect mail.$domain:993 -servername mail.$domain 2>/dev/null | grep 'subject\|issuer'"
done
echo "============================================================"