Add rspamd, ClamAV and sentinel Valkey to the mail namespace (#542)
The smarthost routes all mail through one rspamd: inbound that survived the edge gets the AI (LiteLLM Haiku) pass and is tagged for Stalwart's Junk filing; outbound from the lab and pods is DKIM-signed. - add rspamd (milter via ClusterIP only), ClamAV and a 3-node sentinel Valkey - tag inbound (`X-Spam`, `X-Spam-Status`, `X-Spamd-Result`), reject only viruses, tempfail when ClamAV fails - score inbound against the hop before the edge relays (`external_relay`) - DKIM-sign and skip GPT only for the smarthost's mynetworks sources - elect the highest-offset Valkey on full restart; RDB, 384mb `volatile-ttl` - read a hashed controller password (`password_hash`) Requires `password_hash` in kv `mail/default/rspamd-controller`. Reviewed-on: #542 Co-authored-by: unkin-agent <unkin-agent@unkin.net> Co-committed-by: unkin-agent <unkin-agent@unkin.net>
This commit was merged in pull request #542.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
reject = 15;
|
||||
add_header = 6;
|
||||
greylist = null;
|
||||
@@ -0,0 +1,8 @@
|
||||
clamav {
|
||||
type = "clamav";
|
||||
servers = "clamav.mail.svc.cluster.local:3310";
|
||||
symbol = "CLAM_VIRUS";
|
||||
action = "reject";
|
||||
scan_mime_parts = true;
|
||||
log_clean = false;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
sign_authenticated = false;
|
||||
sign_local = true;
|
||||
sign_inbound = false;
|
||||
use_domain = "header";
|
||||
allow_hdrfrom_mismatch = false;
|
||||
selector = "mail";
|
||||
path = "/etc/rspamd/dkim/$domain.$selector.key";
|
||||
@@ -0,0 +1,8 @@
|
||||
# Edge gateway public IPs (smarthost gateways.cidr): score the first hop before them.
|
||||
enabled = true;
|
||||
rules {
|
||||
EDGE_RELAY {
|
||||
strategy = "ip_map";
|
||||
ip_map = ["192.0.2.1/32", "192.0.2.2/32"];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
rules {
|
||||
CLAMAV_UNAVAILABLE {
|
||||
action = "soft reject";
|
||||
expression = "CLAM_VIRUS_FAIL";
|
||||
message = "Virus scanner unavailable, try again later";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
enabled = true;
|
||||
type = "openai";
|
||||
url = "http://litellm.litellm.svc.cluster.local:4000/v1/chat/completions";
|
||||
api_key = "{= env.LITELLM_API_KEY =}";
|
||||
model = "claude-haiku-4-5";
|
||||
model_parameters = {
|
||||
"claude-haiku-4-5" = {
|
||||
max_tokens = 400,
|
||||
temperature = 0.0,
|
||||
}
|
||||
};
|
||||
timeout = 10s;
|
||||
# Inbound only (settings.conf disables it outbound); only uncertain scores (2 <= score < 12).
|
||||
condition = <<EOD
|
||||
return function(task)
|
||||
local res = task:get_metric_result()
|
||||
if not res then return false, 'no result' end
|
||||
if res.passthrough then return false, 'passthrough' end
|
||||
if res.score < 2 or res.score >= 12 then return false, 'score not uncertain' end
|
||||
return true
|
||||
end
|
||||
EOD
|
||||
@@ -0,0 +1 @@
|
||||
enabled = false;
|
||||
@@ -0,0 +1 @@
|
||||
nrows = 5000;
|
||||
@@ -0,0 +1,30 @@
|
||||
# Outbound sources (smarthost mynetworks): DKIM-signed, scored with reject, no GPT.
|
||||
127.0.0.0/8
|
||||
::1
|
||||
10.42.0.0/16
|
||||
10.10.12.200/32
|
||||
198.18.1.10/32
|
||||
198.18.2.160/27
|
||||
198.18.2.192/27
|
||||
198.18.13.0/24
|
||||
198.18.14.0/24
|
||||
198.18.15.0/24
|
||||
198.18.16.0/24
|
||||
198.18.17.0/24
|
||||
198.18.18.0/24
|
||||
198.18.19.0/24
|
||||
198.18.20.0/24
|
||||
198.18.21.0/24
|
||||
198.18.22.0/24
|
||||
198.18.23.0/24
|
||||
198.18.25.0/24
|
||||
198.18.26.0/24
|
||||
198.18.27.0/24
|
||||
198.18.28.0/24
|
||||
198.18.29.0/24
|
||||
198.18.64.0/24
|
||||
198.18.65.0/24
|
||||
198.18.66.0/24
|
||||
198.18.67.0/24
|
||||
198.18.68.0/24
|
||||
198.18.69.0/24
|
||||
@@ -0,0 +1,2 @@
|
||||
use = ["x-spamd-result", "x-spam-status", "x-spam-level", "authentication-results"];
|
||||
skip_local = true;
|
||||
@@ -0,0 +1,2 @@
|
||||
local_addrs = "/etc/rspamd/local.d/local_networks.map";
|
||||
task_timeout = 20s;
|
||||
@@ -0,0 +1,4 @@
|
||||
sentinels = "rspamd-valkey-sentinel.mail.svc.cluster.local:26379";
|
||||
sentinel_masters_pattern = "^rspamd$";
|
||||
sentinel_watch_time = 10s;
|
||||
servers = "rspamd-valkey-0.rspamd-valkey.mail.svc.cluster.local.:6379";
|
||||
@@ -0,0 +1,19 @@
|
||||
outbound {
|
||||
priority = high;
|
||||
ip_map = "/etc/rspamd/local.d/local_networks.map";
|
||||
apply {
|
||||
symbols_disabled = ["GPT_CHECK"];
|
||||
}
|
||||
}
|
||||
inbound {
|
||||
priority = high;
|
||||
ip_map = "/etc/rspamd/local.d/local_networks.map";
|
||||
inverse = true;
|
||||
apply {
|
||||
symbols_disabled = ["DKIM_SIGNED"];
|
||||
# Tag only; reject stays defined (unreachable by score) so ClamAV's virus reject still applies.
|
||||
actions {
|
||||
reject = 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ruleset = "/etc/rspamd/sa-rules/*.cf";
|
||||
@@ -0,0 +1,3 @@
|
||||
password = "{= env.CONTROLLER_PASSWORD_HASH =}";
|
||||
enable_password = "{= env.CONTROLLER_PASSWORD_HASH =}";
|
||||
allow_file_and_shm_inputs = false;
|
||||
@@ -0,0 +1,2 @@
|
||||
count = 2;
|
||||
allow_file_and_shm_inputs = false;
|
||||
@@ -0,0 +1 @@
|
||||
allow_file_and_shm_inputs = false;
|
||||
Reference in New Issue
Block a user