Skip to content

Latest commit

 

History

History
1030 lines (782 loc) · 33.7 KB

Readme.md

File metadata and controls

1030 lines (782 loc) · 33.7 KB

SLAC 2024 06.-08.05.2024 Berlin


Heinlein Support GmbH

Sichere Mailcluster mit Rspamd und Spamhaus DQS

Workshop auf der SLAC 2024



Enterprise grade mail-cluster with open-source? YES ;)

https://www.heinlein-support.de/blog/enterprise-mail-security-open-source



Links zu den Configs


Redundanter Postfix Cluster

  • Wir trennen bei einer Postfix Infrastruktur gern die Systeme mit Internet-Kommunikation und internen Verbindungen
  • externe Systeme sollten im Idealfall keinen Zugriff interne Systeme haben (bzw. nur zum internen Postfix)
  • interne Mails laufen nicht über Systeme mit Verbindung zum Internet
  • MX Server (eingehend) und Mailout (ausgehend) stehen also in einer DMZ
  • HUB (interner Mailverteiler) steht im internen Netzwerk und kommuniziert auch mit MX und Mailout

Postfix Cluster #1

drawing


Postfix Cluster #2

drawing


Postfix Cluster #3

drawing


Postfix Cluster #4

drawing


Kapselung einzelner Dienste in eigene Systeme oder Container/CGroups

  • Redis reagiert empfindlich wenn der Arbeitsspeicher im System ausgeht
  • File Analyse-Tools wie Anti-Viren Systeme oder VBA/PDF-Analysen können bei der Analyse abstürzen
  • Darum sperren wir diese Tools gern in extra Systeme, Container oder mit anderen Mechanismen ein

Realworld Sizing

  • Wir benötigen nicht zwingend xx VMs für einen wirkungsvollen Cluster
  • die Ideen hinter der Segmentierung/Aufteilung lassen sich auch lassen sich auch mit 2 Systemen hochverfügbar umsetzen
  • es geht vor allem darum mögliche Sicherheitsprobleme zu minimieren und einen effektiven redundanten Cluster aufzubauen

Rspamd Anbindung

  • Um Single Points of Failure zu vermeiden installieren wir den Rspamd Proxy direkt auf dem Postfix System
  • Der Proxy bekommt eine Liste von Rspamd Backends, die lastverteilend angesprochen werden
  • Vorteil: Redundanz und Ausfallsicherheit
  • Jeder Postfix übergibt via milter_macro_daemon_name ein Keyword für seine Aufgabe im Cluster
    • z.B. incoming

Quick Walkthrough Postfix und Rspamd Proxy Config

  • Postfix kümmert sich nur noch um Routing, statische Adressumschreibung und einige RFC Prüfungen
  • TLS sollte forciert werden - ja auch wenn es gegen die RFCs ist ;)
  • Access Maps sind definiert aber leer und nur für den Notfall gedacht
  • nur kleine Unterschiede bei MX, Hub (interne Router), Mailout Server
  • Datenbank Anbindung am besten nur auf den internen Hubs
  • Nutzung von ASCII Listen (texthash) als Lookup Tables
    • heutzutage zu wenig Daten für eine indizierte Datenbank
    • postmap kann nicht vergessen werden ;)

MX Config

  • Configs: relay_domains, verify, ggf. TLS Ausnahmen
smtpd_tls_security_level = may
smtp_tls_security_level = encrypt

# Postfix Lookup Tables / Maps / Databases
relay_domains = texthash:/etc/postfix/maps.d/relay_domains.list
transport_maps = texthash:/etc/postfix/maps.d/transport.list, $relay_domains
smtp_tls_policy_maps = texthash:/etc/postfix/maps.d/tls_policy.list

# Postfix Restrictions
smtpd_recipient_restrictions = 
# Postmaster whitelisten!
  check_recipient_access inline:{
    {postmaster@=permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination,permit}
    {abuse@=permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination,permit}
    },
# Empfaenger whitelisten?
  check_recipient_access texthash:/etc/postfix/maps.d/access_recipient.list,
# Hosts und Absender blacklisten?
  check_client_access cidr:/etc/postfix/maps.d/access_client.cidr,
  check_sender_access texthash:/etc/postfix/maps.d/access_sender.list,


# TLS forcieren - aber Ausnahmen erlauben
  check_sender_access pcre:/etc/postfix/maps.d/access_sender_tls_exclude.pcre,


# Keine unsauberen Mails annehmen!
  reject_non_fqdn_sender,
  reject_non_fqdn_recipient,
  reject_unknown_sender_domain,
  reject_unknown_recipient_domain,
# Unsere Kinderchens erlauben!
  permit_mynetworks,
# Alles andere Relaying verbieten!
  reject_unauth_destination,
# Dynamische Empfängervalidierung
  reject_unverified_recipient,
# Was jetzt noch ist darf durch!
  permit
  • /etc/postfix/maps.d/access_sender_tls_exclude.pcre
# exclude @mailexample.de from the TLS enforcement
/.*@mailexample.de$/i DUNNO

/.*/ reject_plaintext_session

Hub Config

  • Configs: relay_domains, transport, mynetworks, virtual, verify, ggf. TLS Ausnahmen
smtpd_tls_security_level = encrypt
smtp_tls_security_level = encrypt

# Postfix Lookup Tables / Maps / Databases
relay_domains = texthash:/etc/postfix/maps.d/relay_domains.list
transport_maps = texthash:/etc/postfix/maps.d/transport.list, $relay_domains
smtp_tls_policy_maps = texthash:/etc/postfix/maps.d/tls_policy.list
lmtp_tls_policy_maps = texthash:/etc/postfix/maps.d/tls_policy.list
virtual_alias_maps = texthash:/etc/postfix/maps.d/virtual_alias.list

# Postfix Restrictions
smtpd_recipient_restrictions = 
# Postmaster whitelisten!
  check_recipient_access inline:{
    {postmaster@=permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination,permit}
    {abuse@=permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination,permit}
    },
# Empfaenger whitelisten?
  check_recipient_access texthash:/etc/postfix/maps.d/access_recipient.list,
# Hosts und Absender blacklisten?
  check_client_access cidr:/etc/postfix/maps.d/access_client.cidr,
  check_sender_access texthash:/etc/postfix/maps.d/access_sender.list,
# Keine unsauberen Mails annehmen!
  reject_non_fqdn_sender,
  reject_non_fqdn_recipient,
  reject_unknown_sender_domain,
  reject_unknown_recipient_domain,
# Unsere Kinderchens erlauben!
  permit_sasl_authenticated,
  permit_mynetworks,
# Alles andere Relaying verbieten!
  reject_unauth_destination,
# Dynamische Empfängervalidierung
  reject_unverified_recipient,
# Was jetzt noch ist darf durch!
  permit

Mailout Config

  • Configs: transport, mynetworks, ggf. TLS Ausnahmen und Verschärfung (Dane)
smtpd_tls_security_level = encrypt
smtp_tls_security_level = encrypt

# Postfix Lookup Tables / Maps / Databases
transport_maps = texthash:/etc/postfix/maps.d/transport.list
smtp_tls_policy_maps = texthash:/etc/postfix/maps.d/tls_policy.list

# Postfix Restrictions
smtpd_recipient_restrictions = 
# Postmaster whitelisten!
  check_recipient_access inline:{
    {postmaster@=permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination,permit}
    {abuse@=permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination,permit}
    },
# Empfaenger whitelisten?
  check_recipient_access texthash:/etc/postfix/maps.d/access_recipient.list,
# Hosts und Absender blacklisten?
  check_client_access cidr:/etc/postfix/maps.d/access_client.cidr,
  check_sender_access texthash:/etc/postfix/maps.d/access_sender.list,
# Unsere Kinderchens erlauben!
  permit_mynetworks,
# Was jetzt noch ist darf durch!
  permit


Quick Walkthrough Rspamd Proxy Config

  • Rspamd Proxy ist kein eigenständiges Paket
  • es wird der komplette Rspamd installiert
  • wir benötigen aber nur ein paar Anpassungen für Actions, Logging, Timeouts und die Rspamd Backend Config
  • alles andere wird in der rspamd.conf.local.override abgeschaltet

/etc/rspamd/rspamd.conf.local.override:

modules {
  path = "/var/lib/rspamd/modules";
  fallback_path = "/var/lib/rspamd/modules"; # Legacy path
}
lua = "/var/lib/rspamd/modules/nil.lua";

antivirus { enabled=false; }
arc { enabled=false; }
asn { enabled=false; }
aws_s3 { enabled=false; }

...

/etc/rspamd/local.d/worker-proxy.inc:

bind_socket = "127.0.0.1:11332";
bind_socket = "[::1]:11332";

upstream "scan" {
  default = yes;
  hosts = "round-robin:10.0.3.146:11333:1,10.0.3.147:11333:1";
  key = "j4zcyxp84q47n8quhnmshbgaa5esjqu451hipxam49g6fhm5kpgy"; 
  compression = yes;
}


Rspamd - Symbole, Module, Plugins, Funktionen

  • Rspamd denkt in Symbolen
  • Symbole im Rspamd sind wie Objekte, die auszuführende Funktionen haben, Konfigurationen, Beschreibungen, Punkte haben können
  • Symbole lassen sich zur Laufzeit an- und abschalten, logisch verknüpfen oder für forcierte Aktionen nutzen
  • Symbole können in der Main-Phase (nicht pre-filter/post-filter) Dependencies auf andere Symbole haben
    • z.B. DMARC wird erst ausgeführt wenn SPF und DKIM geprüft sind
  • Symbole können einer oder mehreren Gruppen zugeordnet werden

drawing


Rspamd - Composites

  • wirken wie die Meta Rules in Spamassassin und können noch einiges mehr
  • Matching erfolgt als logische Verknüfung auf aktivierte Symbole oder Gruppen
    • expression = "INCOMING & BAD_SUBJECT";
  • Wenn eine logische Verknüpfung true ist kann
    • neues Symbol und Punkte hinzugefügt werden
    • gematchte Symbole entfernen oder deren Score

Rspamd - Actions

  • Rspamd kennt verschiedene Aktionen, die bei der Überschreitung der Summe aller Symbole ausgelöst werden
    • no action
    • greylist (soft reject)
    • add header (hier geht es nicht direkt um Header)
    • rewrite subject
    • reject
  • dazu können je nach MTA auch eigene Aktionen definiert werden (Postfix/Milter z.B. discard, quarantine)

https://rspamd.com/doc/configuration/metrics.html


Rspamd - Force Actions

  • in den Force Actions lassen mit logischen Verknüpfungen (expressions) von Symbolen auch Aktionen unabhängig von Schwellwerten forcieren
    • expression = "CLAMAV_VIRUS & !WHITELIST_ANTIVIRUS";
  • alle in actions definierte Aktionen nutzbar
    • Achtung: ein reject = null; schaltet die Aktion reject ganz ab
  • direkte Aktionen lassen sich auch direkt in verschiedenen Plugins auslösen
    • Antivirus
    • Multimap
    • DMARC
    • Ratelimit
    • Spamtrap

https://rspamd.com/doc/modules/force_actions.html


Warum Aktionen direkt in den Plugins (oft) nicht sinnvoll sind

  • Ausnahmen von den Rejects (Whitelisting) sind nur mit vordefinierten Ausnahmen im Plugin möglich oder gar nicht umsetzbar
  • Frühe Rejects lösen einen Passthrough aus, so dass andere Prüfungen abgebrochen werden
    • eindeutige Spam Mails werden ggf. nicht gelernt
  • Oft werden die Rejects in den Plugins eher pauschal ausgeführt
    • Antivirus z.B. verschlüsselte Mails oder Fehlercodes
    • Ratelimit alle Limits führen zu einem Soft Reject

Indikatoren sammeln und auswerten

  • Wir empfehlen Rspamd viele Indikatoren sammeln zu lassen und diese am Ende des Scan auszuwerten
    • Eine Virus Mail wird vielleicht auch als Spam erkannt und dann auch gelernt
  • Dafür werden Composites und Force Actions intensiv genutzt
  • Ausnahmen lassen sich auf einfache Weise umsetzen
  • Es kann eingehender, ausgehender und interner Traffic einfach unterschieden werden
  • Viren lassen sich z.B. in Spam (zum Lernen) und Malware (einfach ablehnen) kategorisieren
  • Ratelimit Rules können einzeln bewertet werden
    • Ablehnung bei bestimmten Rules
    • Info an den Admin bei anderen Limits
  • solange es keine sehr komplexen Multimaps sind verzichten wir auf Optionen Conditional Maps oder Combined maps

Scoring und Policies beim Rspamd

  • oft sehen wir, dass unerwünsche Anhänge oder Absender mit einem hohen Score zum ablehnen gebracht werden
  • hohe Scores triggern aber auch immer die Lern-Mechanismen des Rspamd
    • Bayes, Fuzzy, Reputation, Neural Network, (Ratelimit)
  • Das möchtet ihr bei der Mail mit .exe von euren Kollegen bestimmt nicht
    • wird spätestens lustig wenn eure Signatur als Spam erkannt wird ;)
  • Ablehnung aus Policy Gründen: Force Actions und höchstens kleiner Score
  • Ablehnung als SPAM: hoher Score (aber bitte mit vielen Indikatoren)
  • Gruppen können als Absicherung in ihrem maximalen Score begrenzt werden
    • z.B. IP ist in fast jeder RBL gelistet
  • Bei Policy und Spam zieht auch die Force Action, aber die Mail wird trotzdem angelernt

Beispiel Multimaps:

  • SENDER_DOMAIN_BLOCKLIST -> reject via force_actions
  • SENDER_DOMAIN_SPAM -> 8.0 Punkte

Rspamd Settings

  • Mit dem Settings Plugin im Rspamd lässt sich ein Scan-Profil erstellen, dass abweichende Schwellwerte hat, bestimmte Funktionen deaktiviert oder explizit aktiviert
  • Oder einfach ein weiteres Symbol als Indikator für Composites oder Force Actions bereits stellt
  • die Settings-Profile können statisch in einer Datei liegen, von einem Webserver abgerufen werden, im Redis hinterlegt sein oder von einer HTTP API abgerufen werden
  • Settings Profile haben ein Matching und eine Priorität sowie eine Sektion für Anpassungen und für zusätzliche Symbole
  • Wir definieren Default Symbole nach ihrer Stelle in der Infrastruktur
    • incoming
    • outgoing
    • internal
  • dazu kommen oft extra Profile für bestimmte Systeme oder um zusätzliche Ausnahmen zu ermöglichen
    • z.B. auf dem Hub - wenn die Mail vom MX kommt
# Default IN - no DKIM sign
INCOMING_DEFAULT {
  id = "INCOMING_DEFAULT";
  priority = low;
 
  request_header = {
    # milter_macro_daemon_name in postfix
    "MTA-Name" = "^incoming_default$";
  }
  apply {
    actions {
      # just an example
      # "rewrite subject" = 13; # Please note the space, NOT an underscore
    }
    symbols_disabled = [
      "DKIM_SIGNED",
    ];
  }
  symbols [
      "INCOMING_DEFAULT",
      "INCOMING"
  ]
}


# Default OUT full + dkim sign
OUTGOING_DEFAULT {
  id = "OUTGOING_DEFAULT";
  priority = low;
  request_header = {
    # milter_macro_daemon_name in postfix
    "MTA-Name" = "^outgoing_default$";
  }
  apply {
    groups_disabled = [
      "dmarc",
    ];
  }
  symbols [
      "OUTGOING_DEFAULT",
      "OUTGOING"
  ]
}

https://rspamd.com/doc/configuration/settings.html


Rspamd - Composites + Force_Actions + Gruppen + Settings

  • Wie kommen wir von einzelnen Indikatoren nun zur Ablehnung einer Mail?

Beispiel Antivirus

  • Indikator: CLAMAV_U_PORCUPINE_MALWARE(8.00){Porcupine.Malware.58486.UNOFFICIAL;}
  • Anstelle des Default Symbols CLAMAV haben wir über die Patterns ein eigenes Symbol für diese Signatur erstellt

/etc/rspamd/local.d/antivirus.conf

clamav {
  ...
  symbol = "CLAMAV"

  patterns {
    ...
    CLAMAV_U_PORCUPINE_MALWARE = '/^Porcupine\.Malware/i';
  }
}
  • Dieses neue Symbol ließe sich jetzt direkt verwenden, aber das ist in der Masse nicht managebar
  • Also nutzen wir Gruppen

/etc/rspamd/local.d/antivirus_group.conf

symbols = {
  "CLAMAV_U_PORCUPINE_MALWARE" {
    description = "ClamAV U ^Porcupine.Malware found";
    weight: 8;
    groups: ["clamav_unofficial", "clamav_u_porcupine", "av_virus_reject", "clamav_u_reject"];
    one_shot: true;
  }
}
  • Die Gruppe av_virus_reject läßt sich nun für den Reject nutzen
  • Ein Score von 8 zeigt außerdem, dass wir diese Signatur eigentlich nur in Spam Mails sehen
  • Matchen der Gruppe in Composites

/etc/rspamd/local.d/composites.conf

GROUP_VIRUS_REJECT {
  expression = "g:av_virus_reject";
  score = 0.0;
  policy = "leave";
  description = "Found a VIRUS_REJECT symbol";
}
  • Ablehnung der Mail dann in den Force Actions

/etc/rspamd/local.d/force_actions.conf

rules {
  VIRUS_REJECT {
    action = "reject";
    expression = "GROUP_VIRUS_REJECT";
    message = "REJECT - virus found (support-id: ${queueid}-${uid.substring(1, 6)})";
    require_action = ["no action", "greylist", "reject", "add header", "soft reject", "rewrite subject", "discard", "quarantine"];
  }
}

https://rspamd.com/doc/modules/antivirus.html


Beispiel Multimap + Settings

  • Ablehnung von bestimmten Anhängen bei eingehenden Mails und wenn der Empfänger nicht auf der Welcomelist steht
  • Indikator: BANNED_EXTENSIONS(0.00){exe;}

/etc/rspamd/local.d/multimap.conf

BANNED_EXTENSIONS {
  # Map banned_extensions.map Example:
  # exe
  # scr

  type = "filename";
  filter = "extension";
  map = "file://$LOCAL_CONFDIR/local.d/maps.d/banned_extensions.map";
  symbol = "BANNED_EXTENSIONS";
  score = 1.0;
  message = "A restricted file type was found";
  #skip_archives = true;
}
  • Wir brauchen hier keine Composites, da wir nicht auf Gruppen matchen
  • Ablehnung der Mail in den Force Actions
  • die beiden anderen Symbole kommen aus den Settings (INCOMING) und einer anderen Multimap (WL_RCPT_BANNED_EXTENSIONS)
rules {
  BANNED_EXTENSIONS {
    action = "reject";
    expression = "INCOMING & BANNED_EXTENSIONS & !WL_RCPT_BANNED_EXTENSIONS";
    message = "REJECT - policy violation - attachment type is forbidden (support-id: ${queueid}-${uid.substring(1, 6)})";

  }
}

https://rspamd.com/doc/configuration/composites.html


Rspamd Selectors

  • Selectors sind kleine Funktionen die sich wie Pipes verketten lassen
  • Damit ist es möglich fast jeden Wert aus einer Mail oder den Scan-Daten abzurufen und sogar noch zu modifizieren
  • Oft können Selectors in den Modulen neben statisch definierten Werten (IP, from) verwendet werden
  • Eigene Selectors können in Lua geschrieben werden
  • Default Module mit Selector Unterstützung
    • multimap
    • ratelimit
    • reputation
    • rbl
    • force_actions (reject message)

Beispiele:

  • Lowercased Subject als HEX und auf die ersten 16 Zeichen reduziert
header('Subject').lower.digest('hex').substring(1, 16)
  • Ein Header Wert verknüpft mit der SMTP-From Domain
  • id würde den Header mit einem String ersetzen .id('test')
  • Effektiv: gibt die SMTP-From Domain zurück wenn X-SG-EID existiert
header("X-SG-EID").id;from("smtp","orig"):domain.get_tld'
  • SHA256 Hashes aller Attachments
attachments(hex,sha256)
  • Matching auf den Wochentag verknüpft mit dem Auth-User
  • gibt 'usernamework' oder gar nichts zurück
user.lower;time('connect', '!%w').in(1, 2, 3, 4, 5).id('work')
  • Werte aus Symbolen (Options) - hier BITCOIN_ADDR
symbol('BITCOIN_ADDR'):options.first

https://rspamd.com/doc/configuration/selectors.html


Rspamd Selectors - eigene Selectors in Lua

  • Source IP - aber nur wenn es eine IPv4 Adresse ist
  • Ginge bestimmt auch mit vordefinierten Selectors und regexp filter ;)
lua_selectors.register_extractor(rspamd_config, "ipv4", {
  get_value = function(task, args)
    local ip = task:get_ip()
    if ip and ip:is_valid() and ip:get_version() == 4 then return ip,'userdata' end
    return nil
  end,
  description = 'Get only ipv4 addresses'
})

https://rspamd.com/doc/lua/lua_selectors.html


Multimap

  • Aktivierung eines Symbols wenn ein Abfragewert gegen eine Map matcht
  • Maps können dabei immer lokale Dateien, Dateien auf Webservern, Redis Daten oder HTTP-API sein
  • Vordefinierte Abfragewerte (IP, From etc) + Filter oder Selectors
    • Man kann quasi jeden Wert auf der Mail oder dem Scan gegen eine Liste matchen lassen
  • Nutzen wir meist als Indikator für Policies
    • Blocklisten
    • Fraud Detection unserer Domains von außen
    • Extensions
  • Selten für das Matching auf SPAM
  • Prefilter (+ reject), Conditional Maps, Combined maps nutzen wir nicht

Beispiel SENDER_IP_BLOCKLIST:

  • reiner Indikator (für die Force Actions) ohne Score
  • Reject aus Policy Gründen
SENDER_IP_BLOCKLIST {
  # Map sender_ip_blocklist.map Example:
  # 10.0.0.1
  # 10.2.0.0/16

  type = "ip";
  map = "file://$LOCAL_CONFDIR/local.d/maps.d/sender_ip_blocklist.map";
}

Beispiel SENDER_DOMAIN_SPAMLIST:

  • Spam Indikator - wir wollen den Score nach oben treiben
SENDER_DOMAIN_SPAMLIST {
  # Map sender_domain_spamlist.map Example:
  # spamdomain.br
  # nextspammer.shop

  type = "from";
  filter = "email:domain";
  map = "file://$LOCAL_CONFDIR/local.d/maps.d/sender_domain_spamlist.map";
  score = 8.0;
}
  • Matching des Mime-Content-Types auf S/Mime / PGP Content mit Custom-Selector
  • Wird dann z.B. für das Umrouten der Mail genutzt
ENCRYPTED_MIME_PART_CT {
  # Map encrypted_mime_part_ct.map Example:
  # /multipart\/signed;.*/i
  # /application\/pkcs7-mime;.*/i
  # /application\/pgp-keys;.*/i

  type = "selector";
    # Achtung 'attachments_ct' ist ein custom selector
  selector = "attachments_ct.uniq";
  map = "file://$LOCAL_CONFDIR/local.d/maps.d/encrypted_mime_part_ct.map";
  symbol = "ENCRYPTED_MIME_PART_CT";
  regexp = true;
}

https://rspamd.com/doc/modules/multimap.html


Ratelimit

  • Ratelimit funktioniert nach dem Leaky Bucket Verfahren
  • Es wird also nicht 1:1 gezählt sondern auch mit einem Vorratsbehälter (Burst) gearbeitet
    • Alternativ für ganz genaues zählen haben wir ein eigenes generisches Modul gebaut (ratecounting)
  • Das macht es manchmal schwieriger nachzuvollziehen wann ein Ratelimit erreicht ist
  • Auch hier die übliche Vorgehensweise:
    • Wir bauen uns beliebige Limits aber ohne Aktion nur als Indikator
    • Das matchen wir über Gruppen (groups.conf) und Force Actions
  • Mit Selectors kann man Limits auf ALLES bauen ;)
  • Wir nutzen wegen schlechter Erfahrungen keine ham_factor_rate und ham_factor_burst mehr
rates {
  ip = {
    # sender IP address
    selector = 'ip';
    # You can define more than one bucket, however, you need to use array syntax only
      bucket = [
        {
          symbol = RATELIMIT_IP_MINUTE;
          burst = 10;
          rate = "20 / 1min";
        },
        {
          symbol = RATELIMIT_IP_HOUR;
          burst = 100;
          rate = "1000 / 1h";
        }
      ]
  }
}

# rate / burst adjustments based on spam result
# we do not change the rates / burst on ham results anymore
max_rate_mult = 10;
max_bucket_mult = 20;

# HAM / SPAM Multiplikator für Rate
ham_factor_rate = "1.00"
spam_factor_rate = "0.96"
# HAM / SPAM Multiplikator für Burst
ham_factor_burst = "1.00"
spam_factor_burst = "0.92"

https://rspamd.com/doc/modules/ratelimit.html


Reputation

  • Reputation kalkuliert die Durchschnittspunkte der vergangenen Mail-Scans für einen Wert
  • Daraus leitet sich dann der Score für Reputation ab
  • Lernt selbstständig und ist bei kleineren Scoren ein sehr schöner automatischer zusätzlicher Indikator
    • Scores in der groups.conf vergeben
  • Mit Selectors baut kann mensch Reputationen auf ALLES bauen (z.B. X-Mailer)

rules {

  ip_reputation = {
    selector "ip" {
    }
    backend "redis" {
    }
    symbol = "IP_REPUTATION";
  }

  sender_replyto_reputation = {
    selector "generic" {
      selector = "header('Reply-To')";
    }
    backend "redis" {
    }
    symbol = "SENDER_REPLYTO_REPUTATION";
  }

  bitcoin_reputation = {
    selector "generic" {
      selector = "symbol('BITCOIN_ADDR'):options.first";
    }
    backend "redis" {
    }
    symbol = "BITCOIN_REPUTATION";
  }

}

https://rspamd.com/doc/modules/reputation.html


Spamhaus DQS

  • Rspamd bringt im Default Configs für Spamhaus ZEN und DBL mit
  • mit dem (kommerziellen) DQS von Spamhaus kommen diese Datenbanken hinzu
    • ZRD - neue Domains
    • AuthBL - IPs die mit Brute-Force aufgefallen sind
    • HBL - Hash Blocklist - File, E-mail, Crypto-Wallets, komplette URLs
    • Subdomains bei DBL
  • Das muss im Rspamd extra konfiguriert werden
  • Spamhaus Configs dafür - https://github.com/spamhaus/rspamd-dqs
    • Wir finden die Umsetzung nicht so schön gelöst und haben das etwas umgebaut ;)
    • Hier wieder: Umsetzung der komplexeren Anteile als Selector!
    • Die benötigten Selectors und Config findet ihr bei der Rspamd Config

rbl.conf rbl_group.conf spamhaus_dqs.lua


DKIM

  • Bei DKIM nutzen wir sehr oft gar keine Domain spezifischen Keys
  • Rspamd kennt einen Fallback, der auf einen generischen Key zurück geht
  • Außerdem kann Rspamd vor der Signierung prüfen ob der richtige Public Key für eine Domain im DNS hinterlegt ist
    • Auch bei dutzenden Domains kann rein über das DNS gesteuert werden ob signiert wird oder nicht
  • Im DNS muss gar kein richtiger TXT Eintrag gemacht werden.
  • Es wird ein zentraler Eintrag gesetzt, der von allen aktiven DKIM Domains dann nur "referenziert" wird.
  • Erstellt zur Sicherheit am Besten auch gleich einen Backup-Key und entsprechende DNS Einstellungen

Beispiel:

  • generischer DNS Eintrag (kein korrekter DKIM DNS Pfad)
DKIM001._domainkey IN TXT ( "v=DKIM1; k=ed25519;" 
  "p=jq9RXxO589TEKlnrylc3eFq5x58xBQjRCl/aYdbwQME="
)

  • CNAME
DKIM001._domainkey.mailexample.de CNAME DKIM001.dkim.mailexample.de
DKIM002._domainkey.mailexample.de CNAME DKIM002.dkim.mailexample.de

DKIM001._domainkey.example.com CNAME DKIM001.dkim.mailexample.de
DKIM002._domainkey.example.com CNAME DKIM002.dkim.mailexample.de

  • dkim_signing.conf
# Default selector to use
selector = "dkim001";

# If true, envelope/header domain mismatch is ignored
allow_hdrfrom_mismatch = true;
allow_hdrfrom_multiple = true;
allow_username_mismatch = true;

sign_authenticated = true;
sign_local = true;
sign_networks = "/etc/rspamd/local.d/maps.d/sign_networks.map"; # or url

use_domain = "header";

# Whether to fallback to global config
try_fallback = true;

# Whether to normalize domains to eSLD
use_esld = false;

# If `true` get pubkey from DNS record and check if it matches private key
check_pubkey = true;

# Set to `false` if you want to skip signing if publick and private keys mismatches
allow_pubkey_mismatch = false;

https://rspamd.com/doc/modules/dkim_signing.html


ARC - Authenticated Received Chain

  • die Idee kaputtes DMARC, DKIM, SPF bei Weiterleitungen zu reparieren bzw abzuschwächen

  • und jeden MTA (Hop) auf dem Weg der Zustellung mittels einer Signatur verifizieren zu können

  • jeder MTA bezieht sich auf die Einträge der vorherigen MTA's

  • Instanznummer (i) bezeichnet die Reihenfolge der ARC Header

  • Jeder MTA hängt analog zu DKIM seine eigene extra Signatur mit seinem eigenen Schlüssel an

ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=ncxs.de;
  s=arc; t=1662545894; h=from:from:reply-to:reply-to:subject:subject:date:date:
  message-id:message-id:to:to:cc:mime-version:mime-version:
  content-type:content-type:dkim-signature;
  bh=blG69kNZ8LiIVEQ+94j5HVyLQhIb2l6zTuMg9kGt+S0=;
  b=zfTNg0LOiq6zf+zGRAryC5qd2UGrBMgVDtE5E6NsyYuKkGcflJ+T5nhOYPYcCa4BBY/zB5
  d0napA3sZ4NthPQmfdvERoctIh1GcJyHaVlkShMuD1F8AHyR24d43wvQvxKLqHVfD11jtv
  JLrFDXXbWG21UjQOeHaijzdjG3xjOdVs06tGJhL9pRckLdvpk/SdOS94JoBLNuMouiXXbJ
  mx60jYGNhKSZt0rTcsDzTIhNBTssXZaPzwcjx6X/TN3spYMawx6cE73lY0P/7wMTuUwj16
  4DZnjIMq5CEoerWOnge0e/Hv3Jvgf3p6gCD7Ap8h6yxRwXg49J+Fj/KGAP9KDg==
  • der aktuelle Status von SPF, DKIM und DMARC wird dokumentiert (kann zwischendrin kaputt gegangen sein)
ARC-Authentication-Results: i=1;
  smtpd-in;
  dkim=pass header.d=amazon.de header.s=llktbq2gwxn3x3xrq5ljspgjk2nc5ajv header.b=ggSqgGHR;
  dkim=pass header.d=amazonses.com header.s=ihchhvubuqgjsxyuhssfvqohv7z3u4hn header.b=GsVmLgqr;
  dmarc=pass (policy=quarantine) header.from=amazon.de;
  spf=pass (smtpd-in: domain of 20220907101812f8fb95bae5cc4c4bb24dc960fe80p0eu-C1N7BPP2IWLHN@bounces.amazon.de 
    designates 54.240.1.68 as permitted sender) 
    smtp mailfrom=20220907101812f8fb95bae5cc4c4bb24dc960fe80p0eu-C1N7BPP2IWLHN@bounces.amazon.de
  • ein extra Seal signiert nur die vorherigen ARC Header und deren Zustand (valid/invalid)
ARC-Seal: i=1; s=arc; d=ncxs.de; t=1662545894; a=rsa-sha256; cv=none;
  b=VrzjYe+zk8xlADwh1P1qkmRDf+UUBLecv9pAfT79RMPvwm//wcTtqiJYUPz5ObGLtRkFwB
  HWLR1JzSOk2s0mlKX1rsUlO3AdysAWJ5OdEMI4UCCt0E7iDrX+kmzSJB/sR93lMxnnI28C
  5rUNn34vde+S188lMzdfT6Z0m18nMn4piVJWNceo0o+dvOlXkcr5vKarrB4Lrs8u9Hvgd3
  4knVXRxGhgRMYOIOfbWj2ogVok4JaqmeMwy4tPmiLJ+OJ/Z6zTrsieLyVZu9lPxPEiPITf
  +rH2Ttu4G0CX8f5N+c/tCRAlpAt2EdFM60McycbTqx9CL0DztyTIg6TMpjAJ6w==
  • Auf dem Zielsystem kann über die Signatur jeder Hop kryptografisch geprüft werden
  • Selbst wenn die DKIM Signatur zum Schluß invalide und der SPF falsch ist, kann sicher gestellt werden, dass alles auf dem 1. externen Hop noch in Ordnung war
  • Bei der Instanz 5 also 5. Hop kann ich krytografisch sicher stellen, dass bei Instanz 1 also 1. externer Hop DKIM valide war
  • vorausgesetzt ich vertraue den Hop die die ARC Signatur einfügen

  • Wir verwenden einfach die DKIM Keys auch in ARC
  • Aber wir signieren jetzt im Namen eurer Domain (eSLD)
  • Derzeit scheint eine Signatur auf den MX ausreichend zu sein
# Default path to key, can include '$domain' and '$selector' variables
path = "/var/lib/rspamd/dkim/$selector.key";
# Default selector to use
selector = "dkim001";

# If false, inbound messages are not selected for signing
sign_inbound = true;
# If false, messages from local networks are not selected for signing
symbol_sign = "ARC_SIGNED";
# Whether to fallback to global config
try_fallback = true;

# Domain to use for ARC signing: can be "header", "envelope", "recipient"
# or a domain name like "server.example.com"
use_domain = "slac.lxc";

# Symbol to add when message is signed
use_esld = false;

https://rspamd.com/doc/modules/arc.html


Bonus: Ratelimit Diagramme

Ratelimit


Ratelimit mit leerem Vorratsbehälter (Burst)

Ratelimit


Ratelimit mit vollem Vorratsbehälter (Burst)

Ratelimit


Ratelimit bei mehreren Rules

Ratelimit