This repository has been archived by the owner on Oct 7, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
main.yml
408 lines (386 loc) · 13.4 KB
/
main.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
#############
# RPM
#############
# Enable rspamd experimental repo
rspamd_experimental: false
rspamd_rpm_url: "https://rspamd.com/rpm{{ rspamd_experimental | ternary('', '-stable') }}/{{ (ansible_distribution == 'Fedora') | ternary('fedora', 'centos') }}-{{ansible_distribution_major_version}}/rspamd.repo"
rspamd_repo: /etc/yum.repos.d/rspamd.repo
#######################
# System configuration
#######################
rspamd_lib_dir: /var/lib/rspamd
rspamd_runtime_dir: "{{ rspamd_lib_dir }}"
rspamd_config_dir: /etc/rspamd
rspamd_local_config_dir: "{{ rspamd_config_dir }}/local.d"
rspamd_user: _rspamd
rspamd_group: "{{ rspamd_user }}"
###################
# Workers
###################
# Change to a higher count if more CPUs. Cannot infer from
# has_low_memory or CPU count, which forces type to string (and bombs JSON).
# https://github.com/ansible/ansible/issues/30366
rspamd_worker_process_count: 1
# Change to a higher count if more CPUs.
rspamd_fuzzy_worker_process_count: 1
# Default logging level
# See https://rspamd.com/doc/configuration/logging.html
# Additional vars set with "rspamd_logging_custom_config" dict
rspamd_logging_level: info
# Ignore
__default_rspamd_worker_socket: "{{ rspamd_runtime_dir }}/rspamd-worker.sock"
# Change to a different server or host if clustered
rspamd_worker_socket: "{{ __default_rspamd_worker_socket }}"
# Controller used by rspamc direct learns
rspamd_controller_socket: "127.0.0.1:11334"
# Fuzzy worker
rspamd_fuzzy_socket: "127.0.0.1:11335"
######################
# Redis configuration
######################
# Enable redis for rspamd. Enable if worker exists on local socket
rspamd_redis_enabled: "{{ (not (has_low_memory | bool) and rspamd_worker_socket.find('/') != -1) | bool }}"
# Give an absolute path to use a UNIX socket + install service
rspamd_redis_runtime_dir: "{{ rspamd_runtime_dir }}/redis"
rspamd_redis_server: "{{ rspamd_redis_runtime_dir }}/redis.sock"
rspamd_redis_pid_file: "{{ rspamd_redis_runtime_dir }}/redis.pid"
rspamd_redis_service: "{{ rspamd_redis_server.find('/') == 0 }}"
rspamd_redis_config: "{{ rspamd_local_config_dir }}/redis-server.conf"
rspamd_redis_user: "{{ rspamd_user }}"
rspamd_redis_password: ""
# Database storage
rspamd_redis_dir: "{{ rspamd_lib_dir }}/redis"
rspamd_redis_memory_allocation: "{{ has_low_memory | ternary('256mb', (ansible_memtotal_mb * 0.5) | string + 'mb')}}"
# rspamd_redis_custom_config
# rspamd_neural_custom_config
# rspamd_reputation_custom_config etc
# Save every 60 seconds if more than 1000 keys change
rspamd_redis_snapshot_policy: &snapshot_policy
rdbchecksum: "yes"
save: |-
60 100
save 900 1
rspamd_redis_vars:
bind: "127.0.0.1"
daemonize: "yes"
unixsocketperm: "0600"
"maxmemory-policy": "volatile-lru"
port: 0
maxmemory: "{{ rspamd_redis_memory_allocation }}"
"protected-mode": "no"
pidfile: "{{ rspamd_redis_pid_file }}"
unixsocket: "{{ (rspamd_redis_server.find('/') == 0) | ternary(rspamd_redis_server, omit) }}"
dir: "{{ rspamd_redis_dir }}"
"rename-command": |
CONFIG ""
<<: *snapshot_policy
#################
# rspamd milter
#################
rspamd_proxy_port: 10003
rspamd_proxy_host: localhost
# Filter mail that originates from sendmail or PHP mail() function
rspamd_filter_outbound: true
# filter mail that comes from the server as well as SRS forwards
rspamd_filter_origination: true
#############
# Learning
#############
# Valid values: standalone, piggyback.
# Setting spamfilter in apnscp-vars.yml to spamassassin implies piggyback
# "piggyback" will feed off SA data
rspamd_method: "{{ (spamfilter == 'spamassassin') and mail_enabled | ternary('piggyback', 'standalone') }}"
# piggyback off results from spamassassin to train algorithm
rspamd_passive_learning_mode: "{{ rspamd_enabled and (rspamd_method == 'piggyback') }}"
# Suitable for low-volume environments
rspamd_use_spamassassin_rules: false
# Learns egregious violators based upon SpamAssassin's scoring
rspamd_piggyback_learn_spam_threshold: 7.0
# Learns roughly half of ham in a trained database
rspamd_piggyback_learn_ham_threshold: -0.5
# Optional location for SA rule usage
rspamd_spamassassin_rules: "/var/lib/spamassassin/3.004002/updates_spamassassin_org/[0-9]*.cf"
# Enable neural training. CPU intensive
rspamd_enable_neural_training: "{{ not has_low_memory and rspamd_redis_enabled }}"
# Autolearn threshold when not piggybacked. Set to false to disable autolearning
rspamd_autolearn_threshold: [-2.5, 10]
# Fuzzy signature storage for detecting spammy attachments
rspamd_fuzzy_learning_active: true
###################
# Action thresholds
###################
# 13.19 is approximately 15% percentile with a trained data set
# n = 532, mu = 18.90, s = 5.39
rspamd_reject_piggyback_score: 25
rspamd_reject_score: 20
# Used when spamfilter == rspamd, triggers delivery in Spam mailbox
# When piggybacking, a SA score of 4 adds this header anyway
rspamd_greylist_piggyback_score: 10
rspamd_greylist_score: 4
rspamd_rewrite_subject_score: 8
# Add headers to email
rspamd_extended_spam_headers: "{{ (rspamd_method == 'piggyback') }}"
# Duration an IP address that revisits the mail server will be
# allowed despite scoring >= rspamd_greylist_score
# Time expressed in seconds, 5 days.
# "5d" would be parsed as a string and converted to 5 seconds
rspamd_greylist_expire: 432000
#################
# Weighted scores
#################
# Various weighted scores maximums. As p → 100%, score → var
rspamd_weight_neural_spam: 3.0
rspamd_weight_neural_ham: -3.0
# Scoring function is sigmoid
rspamd_weight_bayes_spam: 10
rspamd_weight_bayes_ham: -3.0
# Periodically cull infrequently seen symbols from database
rspamd_bayes_expiry_time: 2592000
# Set to true and expiry time to large to defer to Redis in OOM situations
# See https://rspamd.com/doc/modules/bayes_expiry.html
rspamd_bayes_lazy_expire: false
######################
# Learning commands
######################
rspamd_learn_command: /usr/bin/rspamc
rspamd_learn_spam: '"|{{ rspamd_learn_command }} learn_spam"'
rspamd_learn_ham: '"|{{ rspamd_learn_command }} learn_ham"'
rspamd_piggyback_block: |
/^X-Spam-Score: ([-\d\.]+)/
if ($MATCH1 >= {{ rspamd_piggyback_learn_spam_threshold }})
{% raw -%} { {% endraw %}
cc "! {{ rspamd_learn_spam_email }}"
{% raw -%} } {% endraw %}
elsif ($MATCH1 <= {{ rspamd_piggyback_learn_ham_threshold }})
{% raw -%} { {% endraw %}
cc "! {{ rspamd_learn_ham_email }}"
{% raw -%} } {% endraw %}
rspamd_learn_spam_email: "learn_spam"
rspamd_learn_ham_email: "learn_ham"
maildrop_files:
- "{{ (apnscp_account_root + '/site*/fst/etc/maildroprc') | fileglob }}"
- "{{ apnscp_filelists }}/siteinfo/etc/maildroprc"
#####################
# Postfix integration
#####################
rspamd_postfix_config:
# All inbound and forwarded mail
smtpd_milters: "{{ rspamd_enabled | ternary('inet:' + rspamd_proxy_host + ':' + rspamd_proxy_port|string, None) }}"
milter_default_action: accept
# Locally originating mail with sendmail
non_smtpd_milters: "{{ rspamd_enabled and rspamd_filter_outbound | ternary('inet:' + rspamd_proxy_host + ':' + rspamd_proxy_port|string, None) }}"
milter_mail_macros: "i {mail_addr} {client_addr} {client_name} {auth_authen}"
##################
# rspamd config
##################
# When rspamd_use_spamassassin_rules is true
rspamd_spamassassin_config:
- file: spamassassin.conf
vars:
ruleset: "{{ rspamd_spamassassin_rules }}"
match_limit: 100k
config_files:
- file: statistics_group.conf
vars:
symbols:
BAYES_HAM:
weight: "{{ rspamd_weight_bayes_ham }}"
BAYES_SPAM:
weight: "{{ rspamd_weight_bayes_spam }}"
- file: neural_group.conf
vars:
symbols:
NEURAL_SPAM:
weight: "{{ rspamd_weight_neural_spam }}"
NEURAL_HAM:
weight: "{{ rspamd_weight_neural_ham }}"
- file: neural.conf
vars:
enabled: "{{ rspamd_enable_neural_training }}"
servers: "{{ rspamd_redis_server }}"
password: "{{ rspamd_redis_password }}"
dbname: "{{ rspamd_neural_db | default(2) }}"
- file: replies.conf
vars:
action: no action
- file: "url_tags.conf"
vars:
enabled: "{{ rspamd_redis_enabled }}"
- file: reputation.conf
vars:
rules:
ip_reputation:
symbol: IP_REPUTATION
selector:
ip: {}
backend: &redis
redis:
spf_reputation:
symbol: SPF_REPUTATION
selector:
spf: {}
backend: *redis
dkim_reputation:
symbol: DKIM_REPUTATION
selector:
dkim: {}
backend: *redis
- file: actions.conf
vars:
rewrite_subject: "{{ rspamd_rewrite_subject_score }}"
add_header: null
# greylist and reject are computed in enable-rspamd.yml
subject: "{{ rspamd_passive_learning_mode | ternary('%s', '[SPAM] (%d) %s') }}"
- file: classifier-bayes.conf
vars:
backend: "{{ rspamd_redis_enabled | ternary('redis', 'sqlite') }}"
autolearn: "{{ (rspamd_method == 'piggyback') | ternary(false, rspamd_autolearn_threshold) }}"
new_schema: true
name: bayes
expire: "{{ rspamd_bayes_expiry_time }}"
lazy: "{{ rspamd_bayes_lazy_expire }}"
statfile:
BAYES_HAM:
symbol: BAYES_HAM
spam: false
BAYES_SPAM:
symbol: BAYES_SPAM
spam: true
- file: dmarc.conf
vars:
reporting: false
actions:
quarantine:
- add_header
- rewrite_subject
reject: reject
- file: force_actions.conf
vars:
rules:
DMARC_FLAG_QUARANTINE:
action: "rewrite subject"
subject: "[DMARC] (%d) %s"
honor_action: ["add header", "reject"]
expression: "DMARC_POLICY_QUARANTINE"
- file: fuzzy_check.conf
vars:
rule:
local:
servers: "{{ rspamd_fuzzy_socket }}"
symbol: "LOCAL_FUZZY_UNKNOWN"
mime_types: ["application/*", "*/octet-stream"]
max_score: 20
skip_unknown: true
read_only: "{{ not rspamd_fuzzy_learning_active }}"
algorithm: mumhash
fuzzy_map:
LOCAL_FUZZY_DENIED:
max_score: 20
flag: 1
LOCAL_FUZZY_PROB:
max_score: 10
flag: 2
LOCAL_FUZZY_WHITE:
max_score: 2
flag: 3
- file: greylist.conf
vars:
expire: "{{ rspamd_greylist_expire }}"
- file: logging.inc
vars:
level: "{{ rspamd_logging_level }}"
- file: metrics.conf
vars:
group:
fuzzy:
max_score: 12
symbol:
LOCAL_FUZZY_UNKNOWN:
weight: 3
description: Generic fuzzy hash match
LOCAL_FUZZY_DENIED:
weight: 12
description: Denied fuzzy hash
LOCAL_FUZZY_PROB:
weight: 6
description: Probable fuzzy hash
LOCAL_FUZZY_WHITE:
weight: -2.5
description: Whitelisted fuzzy hash
MX:
symbol:
MX_MISSING:
score: 2
description: No MX record
one_shot: true
MX_GOOD:
score: -0.01
description: MX record valid
one_shot: true
MX_INVALID:
score: 1
description: MX found but could not connect
one_shot: true
- file: milter_headers.conf
vars:
extended_spam_headers: "{{ rspamd_extended_spam_headers | bool }}"
use: ['x-spam-score','spam-header']
routines:
spam-header:
header: "X-Spam-Flag"
value: "Yes"
custom:
x-spam-score: |
return function(task, common_meta)
local sc = common_meta['metric_score'] or task:get_metric_score()
-- return no error
return nil,
-- header(s) to add
{['X-Spam-Score'] = string.format('%.2f', sc[1])},
-- header(s) to remove
{['X-Spam-Score'] = 1},
-- metadata to store
{}
end
- file: mx_check.conf
vars:
timeout: 5
symbol_bad_mx: "MX_INVALID"
symbol_no_mx: "MX_MISSING"
symbol_good_mx: "MX_GOOD"
expire: 86400
key_prefix: "rmx"
enabled: true
- file: redis.conf
vars: &redis_vars
servers: "{{ rspamd_redis_enabled | ternary(rspamd_redis_server, None) }}"
password: "{{ rspamd_redis_password }}"
expand_keys: true
- file: worker-fuzzy.inc
vars:
backend: "{{ rspamd_redis_enabled | ternary('redis', 'sqlite') }}"
count: "{{ rspamd_fuzzy_worker_process_count }}"
hash_file: "{{ rspamd_redis_enabled | ternary(omit, '${DBDIR}/fuzzy.db') }}"
bind_socket: "{{ rspamd_fuzzy_socket }}"
- file: worker-normal.inc
vars:
enabled: "{{ not has_low_memory }}"
bind_socket: "{{ rspamd_worker_socket }}"
- file: worker-proxy.inc
vars:
self_scan: "{{ (has_low_memory and (__default_rspamd_worker_socket == rspamd_worker_socket )) }}"
bind_socket: "localhost:{{ rspamd_proxy_port }}"
spam_header: 'X-Spam-Flag'
upstream:
local:
default: true
hosts: "{{ rspamd_worker_socket }}"
- file: worker-controller.inc
vars:
# Does this affect just outbound or inbound?
quarantine_on_reject: false
bind_socket: "127.0.0.1:11334"
#bind_socket: "{{ rspamd_runtime_dir }}/rspamd-controller.sock"
count: "{{ rspamd_worker_process_count }}"
# Dependency marker
mail_rspamd_marker: true