diff --git a/hieradata/os/AlmaLinux/all_releases.yaml b/hieradata/os/AlmaLinux/all_releases.yaml index 3ff5da7..c09e0ee 100644 --- a/hieradata/os/AlmaLinux/all_releases.yaml +++ b/hieradata/os/AlmaLinux/all_releases.yaml @@ -147,6 +147,18 @@ profiles::yum::global::repos: baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/postgresql/common/redhat/rhel-%{facts.os.release.major}-%{facts.os.architecture} gpgkey: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/postgresql/keys/PGDG-RPM-GPG-KEY-RHEL + # Rspamd repositories + rspamd: + ensure: absent + name: rspamd + descr: rspamd repository + target: /etc/yum.repos.d/rspamd.repo + baseurl: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/rspamd/rpm-stable/centos-%{facts.os.release.major}/x86_64 + gpgkey: https://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/rspamd/rpm/rspamd.asc + gpgcheck: 1 + repo_gpgcheck: 1 + mirrorlist: absent + # Ceph repositories ceph: ensure: absent diff --git a/hieradata/roles/infra/mail/gateway.yaml b/hieradata/roles/infra/mail/gateway.yaml index 89e459b..0dcd981 100644 --- a/hieradata/roles/infra/mail/gateway.yaml +++ b/hieradata/roles/infra/mail/gateway.yaml @@ -1,4 +1,58 @@ --- +hiera_include: + - redis + +profiles::yum::global::repos: + rspamd: + ensure: present + +# local redis for rspamd bayes and history; bayes tokens carry a ttl so volatile-ttl can evict +redis::maxmemory: '128mb' +redis::maxmemory_policy: 'volatile-ttl' + +# local rspamd, deterministic checks only; module defaults cover spf/dkim/dmarc/arc/rbl/phishing/mime_types/fuzzy_check +profiles::rspamd::edge::rules: + edge.cf: 'https://git.unkin.net/unkin/rspamd-rules/raw/branch/main/edge.cf' +profiles::rspamd::edge::local_d: + worker-proxy.inc: | + bind_socket = "127.0.0.1:11332"; + milter = yes; + timeout = 120s; + count = 1; + upstream "local" { + default = yes; + self_scan = yes; + } + worker-normal.inc: | + enabled = false; + redis.conf: | + servers = "127.0.0.1:6379"; + actions.conf: | + reject = 13; + add_header = 6; + rewrite_subject = null; + greylist = null; + greylist.conf: | + enabled = false; + gpt.conf: | + enabled = false; + classifier-bayes.conf: | + backend = "redis"; + expire = 8640000; + autolearn { + spam_threshold = 6.0; + ham_threshold = -0.5; + check_balance = true; + } + spamassassin.conf: | + ruleset = "/etc/rspamd/rules/*.cf"; + alpha = 0.1; + settings.conf: | + smarthost_outbound { + priority = high; + ip = "103.216.191.185"; + want_spam = yes; + } # base postfix configuration (passed to postfix class) postfix::relayhost: 'direct' diff --git a/site/profiles/manifests/rspamd/edge.pp b/site/profiles/manifests/rspamd/edge.pp new file mode 100644 index 0000000..c3a248e --- /dev/null +++ b/site/profiles/manifests/rspamd/edge.pp @@ -0,0 +1,68 @@ +# local rspamd milter for the mail edge gateways +# - local_d: /etc/rspamd/local.d file name => content +# - rules: /etc/rspamd/rules file name => url, re-fetched every puppet run; fetch failures keep the last good copy +class profiles::rspamd::edge ( + Hash[String, String] $local_d = {}, + Hash[String, Stdlib::HTTPSUrl] $rules = {}, +) { + + package { 'rspamd': + ensure => installed, + } + + $local_d.each |$name, $content| { + file { "/etc/rspamd/local.d/${name}": + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + content => $content, + require => Package['rspamd'], + notify => Service['rspamd'], + } + } + + file { '/etc/rspamd/rules': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + require => Package['rspamd'], + } + + $rules.each |$name, $url| { + $path = "/etc/rspamd/rules/${name}" + + # empty placeholder so rspamd starts before the first successful fetch + file { $path: + ensure => file, + owner => 'root', + group => 'root', + mode => '0644', + content => '', + replace => false, + } + + # a failed or unchanged fetch skips the swap without failing the run + exec { "rspamd_rules_fetch_${name}": + command => "/usr/bin/mv -f ${path}.new ${path}", + onlyif => "/usr/bin/curl -fsS --max-time 30 -o ${path}.new ${url} && ! /usr/bin/cmp -s ${path}.new ${path}", + require => File[$path], + notify => Exec['rspamd_reload'], + } + } + + # reload keeps the milter answering while config changes apply + service { 'rspamd': + ensure => running, + enable => true, + restart => '/usr/bin/systemctl reload rspamd', + require => Package['rspamd'], + } + + exec { 'rspamd_reload': + command => '/usr/bin/systemctl reload rspamd', + refreshonly => true, + require => Service['rspamd'], + } +} diff --git a/site/roles/manifests/infra/mail/gateway.pp b/site/roles/manifests/infra/mail/gateway.pp index e046920..37ac4e4 100644 --- a/site/roles/manifests/infra/mail/gateway.pp +++ b/site/roles/manifests/infra/mail/gateway.pp @@ -6,6 +6,7 @@ class roles::infra::mail::gateway { }else{ include profiles::defaults include profiles::base + include profiles::rspamd::edge include profiles::postfix::gateway } }