diff --git a/DMS/docker-compose.yml b/DMS/docker-compose.yml index 6318083..8152095 100644 --- a/DMS/docker-compose.yml +++ b/DMS/docker-compose.yml @@ -26,7 +26,13 @@ services: - ./docker-data/dms/mail-state/:/var/mail-state/ - ./docker-data/dms/mail-logs/:/var/log/mail/ - ./docker-data/dms/config/:/tmp/docker-mailserver/ - - ./docker-data/dms/config/dovecot/conf.d/95-sieve-redirect.conf:/etc/dovecot/conf.d/95-sieve-redirect.conf:ro + # ENTFERNT: Mount von dovecot/conf.d/95-sieve-redirect.conf + # Der Host-Pfad existiert nicht, Docker hat daraufhin ein VERZEICHNIS + # unter /etc/dovecot/conf.d/95-sieve-redirect.conf angelegt (nachweisbar + # per `docker exec mailserver cat ...` -> "Is a directory"). Der Mount war + # also wirkungslos. Falls dort spaeter wirklich etwas gebraucht wird + # (z.B. sieve_redirect_envelope_from), erst die Datei auf dem Host + # anlegen, dann den Mount wieder aufnehmen. - /etc/localtime:/etc/localtime:ro - ./sync_dynamodb_to_sieve.py:/scripts/sync.py:ro - ./sieve-cron:/etc/cron.d/sieve-sync:ro @@ -65,7 +71,12 @@ services: - SSL_KEY_PATH=/etc/mail/certs/${NODE_HOSTNAME}/${NODE_HOSTNAME}.key # SPAM / Rspamd - - ENABLE_OPENDKIM=1 + # OpenDKIM deaktiviert: es liegen keine Keys unter config/opendkim/, der + # Milter hat also nie etwas signiert. Ausgehende Mail wird von Amazon SES + # signiert (Easy DKIM), eingehende DKIM-Pruefung macht rspamd selbst. + # DMS warnt beim Start ausdruecklich davor, OpenDKIM parallel zu rspamd + # zu betreiben. + - ENABLE_OPENDKIM=0 - ENABLE_OPENDMARC=0 - ENABLE_POLICYD_SPF=0 - ENABLE_RSPAMD=1 diff --git a/DMS/docker-data/dms/config/rspamd/append.d/settings.conf b/DMS/docker-data/dms/config/rspamd/append.d/settings.conf new file mode 100644 index 0000000..bd8e4bc --- /dev/null +++ b/DMS/docker-data/dms/config/rspamd/append.d/settings.conf @@ -0,0 +1,80 @@ +# DMS-CUSTOM-APPEND +# =========================================================================== +# WICHTIG: Diese Datei wird von user-patches.sh an /etc/rspamd/local.d/settings.conf +# ANGEHAENGT und nicht darueber kopiert. DMS legt in dieser Datei selbst eine +# Regel fuer authentifizierte User ab (DMS::SED_TAG::1), die erhalten bleiben muss. +# =========================================================================== +# +# Hintergrund +# ----------- +# Externe Mail erreicht DMS nie direkt: SES -> S3/SQS -> email-worker -> SMTP. +# Rspamd sieht als Client-IP daher immer den Worker-Container (172.x) statt des +# echten Absender-Servers. Alle verbindungsbezogenen Pruefungen messen damit +# unsere eigene Infrastruktur und liefern systematisch Strafpunkte: +# +# HFILTER_HOSTNAME_UNKNOWN 6.0 (kein PTR fuer 172.x -> exakt die add_header-Schwelle) +# R_SPF_FAIL / R_SPF_SOFTFAIL 4.5 / 2.5 +# R_DKIM_NA / R_DKIM_PERMFAIL 1.0 / 4.5 +# +# Diese Gruppen werden fuer Einlieferungen aus dem Docker-Netz deaktiviert. +# Inhaltsbezogene Pruefungen (Bayes, Fuzzy, URL-/Surbl-Blocklisten, MIME, +# Attachment-Checks) bleiben vollstaendig aktiv - echter Spam wird also weiter +# erkannt, nur eben anhand des Inhalts statt anhand einer Transportstrecke, +# die rspamd hier gar nicht beurteilen kann. +# +# SPF/DKIM/DMARC gehen dadurch nicht verloren: SES prueft sie bereits mit der +# echten Absender-IP. Das Ergebnis liegt im SQS-Payload (receipt.spamVerdict, +# spfVerdict, dkimVerdict, dmarcVerdict). Sobald der Worker diese Verdicts als +# Header stempelt, koennen sie hier per multimap wieder bepunktet werden. + +# --------------------------------------------------------------------------- +# 1) Einlieferungen des email-workers (externe Mail + dessen Forwards/OOO) +# +# Der Worker setzt X-SES-Worker-Processed auf JEDER Mail, die er einliefert: +# delivered = Originalmail an das lokale Postfach +# forwarded = neu komponierte Weiterleitung (rules-processor.ts) +# ooo-reply = Abwesenheitsantwort +# +# Die IP-Bedingung ist die Absicherung: ohne sie koennte ein externer Absender +# den Header selbst setzen und die Auth-Pruefungen abschalten. Beide +# Bedingungen werden von rspamd implizit mit UND verknuepft. +# --------------------------------------------------------------------------- +ses_worker_injected { + priority = 10; + ip = ["172.16.0.0/12", "127.0.0.0/8"]; + header = { + "X-SES-Worker-Processed" = true; + } + apply { + groups_disabled = ["spf", "dkim", "dmarc", "hfilter"]; + symbols_disabled = ["RDNS_NONE"]; + } +} + +# --------------------------------------------------------------------------- +# 2) Lokale Re-Injection ohne Worker-Header +# +# Betrifft: +# - Sieve-Redirects fuer INTERNE Mail (accounting@ -> support@ -> Forwards). +# Diese Mail laeuft nie ueber SES/Worker, hat also keinen Worker-Header. +# - Roundcube, das ohne SASL-Auth aus dem Docker-Netz einliefert +# (ROUNDCUBEMAIL_SMTP_USER ist bewusst leer). +# +# Beides wurde bisher von der DOCKER_WL-Whitelist (-50) aufgefangen. Diese +# Regel ersetzt sie - deutlich enger gefasst, weil sie an das Docker-Netz +# gebunden ist statt an eine faelschbare Absenderdomain. +# +# Niedrigere Prioritaet als Regel 1: rspamd wertet Regeln nach Prioritaet aus +# und nimmt den ersten Treffer, Worker-Mail landet also nie hier. +# +# ACHTUNG: Diese Regel setzt voraus, dass Port 25 NICHT oeffentlich erreichbar +# ist (docker-compose.yml bindet ihn auf 127.0.0.1). Wird das je geaendert, +# muss diese Regel weg - sonst umgeht jeder externe Absender die Pruefung. +# --------------------------------------------------------------------------- +local_reinjection { + priority = 5; + ip = ["172.16.0.0/12", "127.0.0.0/8"]; + apply { + groups_enabled = ["dkim"]; + } +} diff --git a/DMS/docker-data/dms/config/rspamd/local.d/logging.inc b/DMS/docker-data/dms/config/rspamd/local.d/logging.inc new file mode 100644 index 0000000..4fe97d2 --- /dev/null +++ b/DMS/docker-data/dms/config/rspamd/local.d/logging.inc @@ -0,0 +1,19 @@ +# documentation: https://rspamd.com/doc/configuration/logging.html +# +# Uebersteuert den DMS-Default (level = "silent"), bei dem rspamd ueberhaupt +# nichts protokolliert und Spam-Scores nicht nachvollziehbar sind. +# +# type = "console" bleibt bewusst stehen: Supervisor leitet stdout/stderr von +# rspamd bereits nach /var/log/mail/rspamd.log um (siehe dms-services.conf). +# Ein eigenes type = "file" mit demselben Pfad haette zwei Schreiber auf +# derselben Datei zur Folge. +# +# Mit level = "info" schreibt rspamd pro Mail eine Zeile mit Aktion, Score und +# allen ausgeloesten Symbolen samt Einzelgewicht: +# +# docker exec mailserver sh -c 'grep rspamd_task_write_log /var/log/mail/rspamd.log | tail -20' + +type = "console"; +level = "info"; +color = false; +systemd = false; diff --git a/DMS/docker-data/dms/config/rspamd/local.d/multimap.conf b/DMS/docker-data/dms/config/rspamd/local.d/multimap.conf index c7ec77c..fab6bf9 100644 --- a/DMS/docker-data/dms/config/rspamd/local.d/multimap.conf +++ b/DMS/docker-data/dms/config/rspamd/local.d/multimap.conf @@ -1,8 +1,18 @@ -DOCKER_WL { - type = "from"; - filter = "email:domain"; - map = "/etc/rspamd/override.d/docker_whitelist.map"; - symbol = "DOCKER_WHITELIST"; - description = "Whitelist fuer eigene Domains"; - score = -50.0; -} \ No newline at end of file +# documentation: https://rspamd.com/doc/modules/multimap.html +# +# Die fruehere Regel DOCKER_WL (-50 Punkte fuer jede Mail, deren Envelope-From +# auf eine unserer eigenen Domains zeigt) ist bewusst entfernt worden: +# +# 1. Sie war ein Spoofing-Loch. Mit SPOOF_PROTECTION=0 genuegte einem +# beliebigen externen Absender ein "MAIL FROM: ", um +# -50 Punkte plus das erzwungene "no action" aus force_actions.conf zu +# bekommen - also garantierte Zustellung in die Inbox. +# 2. Sie hat echten Spam an weitergeleitete Adressen durchgereicht, weil der +# email-worker seine Weiterleitungen mit Envelope-From = Empfaengeradresse +# (also eigene Domain) einliefert. +# 3. Sie hat nur ein Symptom kompensiert: die falschen Auth-/Hostname-Scores, +# die entstehen, weil alle Mail aus dem Worker-Container kommt. Das wird +# jetzt an der Ursache geloest - siehe rspamd/append.d/settings.conf. +# +# Die Datei bleibt (leer) bestehen, damit user-patches.sh sie beim Start ueber +# eine evtl. noch im Container liegende alte Version kopiert. diff --git a/DMS/docker-data/dms/config/rspamd/override.d/force_actions.conf b/DMS/docker-data/dms/config/rspamd/override.d/force_actions.conf index 49c76bc..458bdb0 100644 --- a/DMS/docker-data/dms/config/rspamd/override.d/force_actions.conf +++ b/DMS/docker-data/dms/config/rspamd/override.d/force_actions.conf @@ -1,6 +1,10 @@ -rules { - DOCKER_WHITELIST_FORCE { - action = "no action"; - expression = "DOCKER_WHITELIST"; - } -} \ No newline at end of file +# documentation: https://rspamd.com/doc/modules/force_actions.html +# +# Die Regel DOCKER_WHITELIST_FORCE ("no action" sobald DOCKER_WHITELIST greift) +# ist entfernt. Sie hat die Spam-Entscheidung fuer jede Mail mit eigener +# Absenderdomain hart ueberschrieben - inklusive echtem Spam an weitergeleitete +# Adressen. Das dazugehoerige Symbol existiert nicht mehr, siehe +# rspamd/local.d/multimap.conf. +# +# Keine rules{}-Sektion = force_actions ist wirkungslos. Datei bleibt bestehen, +# damit DMS sie beim Start ueber eine alte Version im Container kopiert. diff --git a/DMS/docker-data/dms/config/user-patches.sh b/DMS/docker-data/dms/config/user-patches.sh index d1ea6e2..1dc923d 100755 --- a/DMS/docker-data/dms/config/user-patches.sh +++ b/DMS/docker-data/dms/config/user-patches.sh @@ -1,47 +1,61 @@ #!/bin/bash -# user-patches.sh laeuft bei jedem Start von DMS automatisch +# user-patches.sh laeuft bei jedem Start von DMS automatisch, +# nach dem Setup und bevor die Daemons gestartet werden. -ACCOUNTS_FILE="/tmp/docker-mailserver/postfix-accounts.cf" -WHITELIST_FILE="/etc/rspamd/override.d/docker_whitelist.map" +SRC_BASE="/tmp/docker-mailserver/rspamd" +LOCAL_D="/etc/rspamd/local.d" -# --- Rspamd Whitelist generieren --- -STATIC_DOMAINS=( - "bayarea-cc.com" - "ruehrgedoens.de" - "annavillesda.org" - "bizmatch.net" - "biz-match.com" - "qrmaster.net" - "nqsltd.com" - "iitwelders.com" -) - -echo "Patching: Generiere Rspamd Whitelist aus Accounts + statischen Domains..." - -{ - for domain in "${STATIC_DOMAINS[@]}"; do - echo "$domain" - done - if [ -f "$ACCOUNTS_FILE" ]; then - awk -F'|' '{print $1}' "$ACCOUNTS_FILE" | cut -d'@' -f2 - fi -} | sort | uniq > "$WHITELIST_FILE" - -chmod 644 "$WHITELIST_FILE" -chown _rspamd:_rspamd "$WHITELIST_FILE" 2>/dev/null || true -echo "Whitelist erstellt:" -cat "$WHITELIST_FILE" - -# --- local.d configs manuell kopieren (DMS kopiert local.d nicht automatisch) --- +# --------------------------------------------------------------------------- +# 1) local.d configs kopieren +# DMS kopiert nur rspamd/override.d automatisch, local.d nicht. +# --------------------------------------------------------------------------- echo "Patching: Kopiere custom rspamd local.d configs..." -SRC="/tmp/docker-mailserver/rspamd/local.d" -DST="/etc/rspamd/local.d" -if [ -d "$SRC" ]; then - for f in "$SRC"/*; do +if [ -d "${SRC_BASE}/local.d" ]; then + for f in "${SRC_BASE}/local.d"/*; do [ -f "$f" ] || continue - cp "$f" "$DST/$(basename "$f")" - chown root:root "$DST/$(basename "$f")" - chmod 644 "$DST/$(basename "$f")" - echo " Kopiert: $(basename "$f") -> $DST/" + base=$(basename "$f") + cp "$f" "${LOCAL_D}/${base}" + chown root:root "${LOCAL_D}/${base}" + chmod 644 "${LOCAL_D}/${base}" + echo " Kopiert: ${base} -> ${LOCAL_D}/" done -fi \ No newline at end of file +fi + +# --------------------------------------------------------------------------- +# 2) append.d: an bestehende local.d-Dateien ANHAENGEN statt sie zu ersetzen +# +# Zwingend fuer settings.conf: DMS legt dort selbst die Regel fuer +# authentifizierte User ab (DMS::SED_TAG::1). Ein cp darueber wuerde sie +# loeschen und RSPAMD_CHECK_AUTHENTICATED=0 wirkungslos machen. +# +# Der Marker DMS-CUSTOM-APPEND macht das Anhaengen idempotent - /etc/rspamd +# liegt im Container-Dateisystem und ueberlebt einen `docker restart`. +# --------------------------------------------------------------------------- +echo "Patching: Haenge custom rspamd Snippets an local.d configs an..." +if [ -d "${SRC_BASE}/append.d" ]; then + for f in "${SRC_BASE}/append.d"/*; do + [ -f "$f" ] || continue + base=$(basename "$f") + target="${LOCAL_D}/${base}" + + if grep -q 'DMS-CUSTOM-APPEND' "$target" 2>/dev/null; then + echo " Bereits vorhanden, uebersprungen: ${base}" + continue + fi + + printf '\n' >>"$target" + cat "$f" >>"$target" + chown root:root "$target" + chmod 644 "$target" + echo " Angehaengt: ${base} -> ${target}" + done +fi + +# --------------------------------------------------------------------------- +# HINWEIS: Die frueher hier erzeugte Rspamd-Whitelist +# (/etc/rspamd/override.d/docker_whitelist.map aus postfix-accounts.cf + +# statischer Domainliste) ist entfernt. Die zugehoerige multimap-Regel +# DOCKER_WL (-50) und das erzwungene "no action" aus force_actions.conf gibt +# es nicht mehr - sie waren ein Spoofing-Loch und haben echten Spam an +# weitergeleitete Adressen durchgereicht. Ersatz: rspamd/append.d/settings.conf. +# ---------------------------------------------------------------------------