test / test (push) Canceled after 0s
The routine kept the key after its first read. SelfPost makes a new key when the file is lost or damaged, or a backup brings back another, and rspamd would then have gone on signing with the old one - every verdict unrecorded - until someone restarted the sidecar. The file is one short line; reading it per message costs nothing worth keeping a copy for. The guide says what never needs doing: nothing of rspamd's is cleared after a change of the lists or the key; a restart is for a change of its own configuration only. Prompted by the owner's question whether rspamd's cache needs clearing (2026-10-12). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
46 lines
2.0 KiB
Plaintext
46 lines
2.0 KiB
Plaintext
# Mounted into the sidecar as /etc/rspamd/local.d/milter_headers.conf.
|
|
#
|
|
# rspamd writes its verdict into two headers of every message it lets through:
|
|
# the action it chose and the score with the symbols behind it. SelfPost's
|
|
# inbound journal reads them (Inbound > Log shows them next to the message),
|
|
# and the upstream mailbox server receives them with the mail.
|
|
#
|
|
# rspamd removes headers of these names that a sender wrote himself before it
|
|
# adds its own. Without this file the journal still lists accepted mail, with
|
|
# no verdict next to it.
|
|
#
|
|
# The third header is the proof that the other two are rspamd's. The filter is
|
|
# attached so that mail still flows when it is down, and then nothing removes
|
|
# what a sender wrote: he could send his own verdict. So rspamd signs each
|
|
# message - an HMAC-SHA256 of the message's queue id under a key SelfPost
|
|
# generates and leaves in the directory it shares with this container - and
|
|
# SelfPost reads a verdict only next to a signature it can recompute. The
|
|
# signature travels on with the mail and is of no use to whoever sees it: it
|
|
# fits that one queue id.
|
|
use = ["x-spamd-result", "x-rspamd-action", "selfpost-signature"];
|
|
|
|
custom {
|
|
selfpost-signature = <<EOD
|
|
return function(task, common_meta)
|
|
local remove = { ['X-SelfPost-Filter'] = 0 }
|
|
-- The key is read for every message and kept nowhere: SelfPost may make a
|
|
-- new one (the file was lost, a backup was restored), and a key remembered
|
|
-- here would go on signing what SelfPost no longer accepts until someone
|
|
-- restarted this container. The file is one short line.
|
|
local key
|
|
local f = io.open('/etc/rspamd/selfpost/filter.key', 'r')
|
|
if f then
|
|
key = f:read('*l')
|
|
f:close()
|
|
end
|
|
local qid = task:get_queue_id()
|
|
if not key or key == '' or not qid or qid == '' then
|
|
return nil, {}, remove, {}
|
|
end
|
|
local hash = require "rspamd_cryptobox_hash"
|
|
local sig = hash.create_specific_keyed(key, 'sha256', qid):hex()
|
|
return nil, { ['X-SelfPost-Filter'] = sig }, remove, {}
|
|
end
|
|
EOD;
|
|
}
|