mailsystem: Configure rspamd as spam filter

This commit is contained in:
Thomas Preisner 2024-12-05 14:10:04 +01:00
parent b7fac23bd1
commit 6e0947b3a4
6 changed files with 143 additions and 2 deletions

View file

@ -7,4 +7,7 @@ in rec {
dovecotDynamicStateDir = "/var/lib/dovecot";
dovecotDynamicPasswdFile = "${dovecotDynamicStateDir}/passwd";
rspamdProxySocket = "/run/rspamd-proxy.sock";
rspamdControllerSocket = "/run/rspamd-controller.sock";
}

View file

@ -158,8 +158,11 @@ in {
imports = [
./dovecot.nix
./kresd.nix
./nginx.nix
./postfix.nix
./redis.nix
./rspamd.nix
./user.nix
];
}

11
mailsystem/kresd.nix Normal file
View file

@ -0,0 +1,11 @@
{
config,
lib,
...
}: let
cfg = config.mailsystem;
in {
config = lib.mkIf cfg.enable {
services.kresd.enable = true;
};
}

View file

@ -154,6 +154,16 @@ in {
# Configure a non-blocking source of randomness
tls_random_source = "dev:/dev/urandom";
smtpd_milters = [
"unix:${rspamdProxySocket}"
];
# Also use milter for outgoing mails (for e.g., dkim)
non_smtpd_milters = [
"unix:${rspamdProxySocket}"
];
milter_protocol = "6";
milter_mail_macros = "i {mail_addr} {client_addr} {client_name} {auth_type} {auth_authen} {auth_author} {mail_addr} {mail_host} {mail_mailer}";
# Fix for https://www.postfix.org/smtp-smuggling.html
smtpd_forbid_bare_newline = "yes";
smtpd_forbid_bare_newline_exclusions = "$mynetworks";
@ -179,9 +189,9 @@ in {
systemd.services.postfix = {
wants = sslCertService;
after =
["dovecot2.service"]
["dovecot2.service" "rspamd.service"]
++ sslCertService;
requires = ["dovecot2.service"];
requires = ["dovecot2.service" "rspamd.service"];
};
networking.firewall = lib.mkIf cfg.openFirewall {

27
mailsystem/redis.nix Normal file
View file

@ -0,0 +1,27 @@
{
config,
lib,
pkgs,
...
}: let
cfg = config.mailsystem;
redisCfg = config.services.redis.servers.rspamd;
rspamdCfg = config.services.rspamd;
in {
config = lib.mkIf cfg.enable {
services.redis.servers.rspamd = {
enable = true;
# Don't accept connections via tcp
port = 0;
unixSocketPerm = 600;
};
# TODO: Run commands as service user instead of as root?
systemd.services.redis-rspamd.serviceConfig.ExecStartPost =
"+"
+ pkgs.writeShellScript "redis-rspamd-postStart" ''
${pkgs.acl.bin}/bin/setfacl -m "u:${rspamdCfg.user}:x" "${builtins.dirOf redisCfg.unixSocket}"
${pkgs.acl.bin}/bin/setfacl -m "u:${rspamdCfg.user}:rw" "${redisCfg.unixSocket}"
'';
};
}

87
mailsystem/rspamd.nix Normal file
View file

@ -0,0 +1,87 @@
{
config,
lib,
pkgs,
...
}:
with (import ./common.nix {inherit config;}); let
cfg = config.mailsystem;
postfixCfg = config.services.postfix;
redisCfg = config.services.redis.servers.rspamd;
rspamdCfg = config.services.rspamd;
genSystemdSocketCfg = name: socketPath: additionalUser: {
description = "rspamd ${name} worker socket";
listenStreams = [socketPath];
requiredBy = ["rspamd.service"];
socketConfig = {
Service = "rspamd.service";
SocketUser = rspamdCfg.user;
SocketMode = 0600;
ExecStartPost =
lib.mkIf (additionalUser != "")
''${pkgs.acl.bin}/bin/setfacl -m "u:${additionalUser}:rw" "${socketPath}"'';
};
};
in {
config = lib.mkIf cfg.enable {
services.rspamd = {
enable = true;
overrides = {
"classifier-bayes.conf" = {
text = ''
autolearn {
spam_threshold = 6.0 # When to learn spam (score >= threshold)
ham_threshold = -2.0 # When to learn ham (score <= threshold)
}
'';
};
"milter_headers.conf" = {
text = ''
# Add headers related to spam-detection
extended_spam_headers = true;
'';
};
"redis.conf" = {
text = ''
servers = "${redisCfg.unixSocket}";
'';
};
};
workers = {
rspamd_proxy = {
bindSockets = ["systemd:rspamd-proxy.socket"];
count = 1; # Do not spawn too many processes of this type
extraConfig = ''
milter = yes; # Enable milter mode
timeout = 120s; # Needed for Milter usually
upstream "local" {
default = yes; # Self-scan upstreams are always default
self_scan = yes; # Enable self-scan
}
'';
};
controller = {
count = 1;
bindSockets = ["systemd:rspamd-controller.socket"];
extraConfig = ''
static_dir = "''${WWWDIR}"; # Serve the web UI static assets
'';
};
};
};
systemd.sockets = {
rspamd-proxy = genSystemdSocketCfg "proxy" rspamdProxySocket postfixCfg.user;
rspamd-controller = genSystemdSocketCfg "controller" rspamdControllerSocket "";
};
systemd.services.rspamd = {
requires = ["redis-rspamd.service"];
after = ["redis-rspamd.service"];
};
};
}