mirror of
https://github.com/docker-mailserver/docker-mailserver.git
synced 2025-07-10 09:24:50 +02:00
rspamd: add feature for adjusting options with a file parsed by DMS (#3059)
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
This commit is contained in:
parent
40e10d755d
commit
bee9e3627d
10 changed files with 448 additions and 95 deletions
|
@ -132,16 +132,31 @@ function _install_dovecot
|
|||
function _install_rspamd
|
||||
{
|
||||
_log 'trace' 'Adding Rspamd package signatures'
|
||||
curl -sSfL https://rspamd.com/apt-stable/gpg.key | gpg --dearmor >/etc/apt/trusted.gpg.d/rspamd.gpg
|
||||
local DEB_FILE='/etc/apt/sources.list.d/rspamd.list'
|
||||
local RSPAMD_PACKAGE_NAME
|
||||
|
||||
echo "deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/rspamd.gpg] http://rspamd.com/apt-stable/ bullseye main" \
|
||||
>/etc/apt/sources.list.d/rspamd.list
|
||||
echo "deb-src [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/rspamd.gpg] http://rspamd.com/apt-stable/ bullseye main" \
|
||||
>>/etc/apt/sources.list.d/rspamd.list
|
||||
# We try getting the most recent version of Rspamd for aarch64 (from an official source, which
|
||||
# is the backports repository). The version for aarch64 is 3.2; the most recent version for amd64
|
||||
# that we get with the official PPA is 3.4.
|
||||
#
|
||||
# Not removing it later is fine as you have to explicitly opt into installing a backports package
|
||||
# which is not something you could be doing by accident.
|
||||
if [[ $(uname --machine) == 'aarch64' ]]
|
||||
then
|
||||
echo '# Official Rspamd PPA does not support aarch64, so we use the Bullseye backports' >"${DEB_FILE}"
|
||||
echo 'deb [arch=arm64] http://deb.debian.org/debian bullseye-backports main' >>"${DEB_FILE}"
|
||||
RSPAMD_PACKAGE_NAME='rspamd/bullseye-backports'
|
||||
else
|
||||
curl -sSfL https://rspamd.com/apt-stable/gpg.key | gpg --dearmor >/etc/apt/trusted.gpg.d/rspamd.gpg
|
||||
local URL='[arch=amd64 signed-by=/etc/apt/trusted.gpg.d/rspamd.gpg] http://rspamd.com/apt-stable/ bullseye main'
|
||||
echo "deb ${URL}" >"${DEB_FILE}"
|
||||
echo "deb-src ${URL}" >>"${DEB_FILE}"
|
||||
RSPAMD_PACKAGE_NAME='rspamd'
|
||||
fi
|
||||
|
||||
_log 'debug' 'Installing Rspamd'
|
||||
apt-get "${QUIET}" update
|
||||
apt-get "${QUIET}" --no-install-recommends install rspamd redis-server
|
||||
apt-get "${QUIET}" --no-install-recommends install "${RSPAMD_PACKAGE_NAME}" 'redis-server'
|
||||
}
|
||||
|
||||
function _install_fail2ban
|
||||
|
|
182
target/scripts/helpers/setup-rspamd.sh
Normal file
182
target/scripts/helpers/setup-rspamd.sh
Normal file
|
@ -0,0 +1,182 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Just a helper to prepend the log messages with `(Rspamd setup)` so
|
||||
# users know exactly where the message originated from.
|
||||
#
|
||||
# @param ${1} = log level
|
||||
# @param ${2} = message
|
||||
function __rspamd__log { _log "${1:-}" "(Rspamd setup) ${2:-}" ; }
|
||||
|
||||
# Run miscellaneous checks against the current configuration so we can
|
||||
# properly handle integration into ClamAV, etc.
|
||||
#
|
||||
# This will also check whether Amavis is enabled and emit a warning as
|
||||
# we discourage users from running Amavis & Rspamd at the same time.
|
||||
function __rspamd__preflight_checks
|
||||
{
|
||||
touch /var/lib/rspamd/stats.ucl
|
||||
|
||||
if [[ ${ENABLE_AMAVIS} -eq 1 ]] || [[ ${ENABLE_SPAMASSASSIN} -eq 1 ]]
|
||||
then
|
||||
__rspamd__log 'warn' 'Running Amavis/SA & Rspamd at the same time is discouraged'
|
||||
fi
|
||||
|
||||
if [[ ${ENABLE_CLAMAV} -eq 1 ]]
|
||||
then
|
||||
__rspamd__log 'debug' 'Enabling ClamAV integration'
|
||||
sedfile -i -E 's|^(enabled).*|\1 = true;|g' /etc/rspamd/local.d/antivirus.conf
|
||||
# RSpamd uses ClamAV's UNIX socket, and to be able to read it, it must be in the same group
|
||||
usermod -a -G clamav _rspamd
|
||||
else
|
||||
__rspamd__log 'debug' 'Rspamd will not use ClamAV (which has not been enabled)'
|
||||
fi
|
||||
}
|
||||
|
||||
# Adjust Postfix's configuration files. Append Rspamd at the end of
|
||||
# `smtpd_milters` in `main.cf`.
|
||||
function __rspamd__adjust_postfix_configuration
|
||||
{
|
||||
# shellcheck disable=SC2016
|
||||
sed -i -E 's|^(smtpd_milters =.*)|\1 inet:localhost:11332|g' /etc/postfix/main.cf
|
||||
}
|
||||
|
||||
# Helper for explicitly enabling or disabling a specific module.
|
||||
#
|
||||
# @param ${1} = module name
|
||||
# @param ${2} = `true` when you want to enable the module (default),
|
||||
# `false` when you want to disable the module [OPTIONAL]
|
||||
# @param ${3} = whether to use `local` (default) or `override` [OPTIONAL]
|
||||
function __rspamd__enable_disable_module
|
||||
{
|
||||
local MODULE=${1:?Module name must be provided}
|
||||
local ENABLE_MODULE=${2:-true}
|
||||
local LOCAL_OR_OVERRIDE=${3:-local}
|
||||
local MESSAGE='Enabling'
|
||||
|
||||
if [[ ! ${ENABLE_MODULE} =~ ^(true|false)$ ]]
|
||||
then
|
||||
__rspamd__log 'warn' "__rspamd__enable_disable_module got non-boolean argument for deciding whether module should be enabled or not"
|
||||
return 1
|
||||
fi
|
||||
|
||||
[[ ${ENABLE_MODULE} == true ]] || MESSAGE='Disabling'
|
||||
|
||||
__rspamd__log 'trace' "${MESSAGE} module '${MODULE}'"
|
||||
cat >"/etc/rspamd/${LOCAL_OR_OVERRIDE}.d/${MODULE}.conf" << EOF
|
||||
# documentation: https://rspamd.com/doc/modules/${MODULE}.html
|
||||
|
||||
enabled = ${ENABLE_MODULE};
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# Disables certain modules by default. This can be overwritten by the user later.
|
||||
# We disable the modules listed in `DISABLE_MODULES` as we believe these modules
|
||||
# are not commonly used and the average user does not need them. As a consequence,
|
||||
# disabling them saves resources.
|
||||
function __rspamd__disable_default_modules
|
||||
{
|
||||
local DISABLE_MODULES=(
|
||||
clickhouse
|
||||
elastic
|
||||
greylist
|
||||
neural
|
||||
reputation
|
||||
spamassassin
|
||||
url_redirector
|
||||
metric_exporter
|
||||
)
|
||||
|
||||
for MODULE in "${DISABLE_MODULES[@]}"
|
||||
do
|
||||
__rspamd__enable_disable_module "${MODULE}" 'false'
|
||||
done
|
||||
}
|
||||
|
||||
# Parses `RSPAMD_CUSTOM_COMMANDS_FILE` and executed the directives given by the file.
|
||||
# To get a detailed explanation of the commands and how the file works, visit
|
||||
# https://docker-mailserver.github.io/docker-mailserver/edge/config/security/rspamd/#with-the-help-of-a-custom-file
|
||||
function __rspamd__handle_modules_configuration
|
||||
{
|
||||
# Adds an option with a corresponding value to a module, or, in case the option
|
||||
# is already present, overwrites it.
|
||||
#
|
||||
# @param ${1} = file name in /etc/rspamd/override.d/
|
||||
# @param ${2} = module name as it should appear in the log
|
||||
# @patam ${3} = option name in the module
|
||||
# @param ${4} = value of the option
|
||||
#
|
||||
# ## Note
|
||||
#
|
||||
# While this function is currently bound to the scope of `__rspamd__handle_modules_configuration`,
|
||||
# it is written in a versatile way (taking 4 arguments instead of assuming `ARGUMENT2` / `ARGUMENT3`
|
||||
# are set) so that it may be used elsewhere if needed.
|
||||
function __add_or_replace
|
||||
{
|
||||
local MODULE_FILE=${1:?Module file name must be provided}
|
||||
local MODULE_LOG_NAME=${2:?Module log name must be provided}
|
||||
local OPTION=${3:?Option name must be provided}
|
||||
local VALUE=${4:?Value belonging to an option must be provided}
|
||||
# remove possible whitespace at the end (e.g., in case ${ARGUMENT3} is empty)
|
||||
VALUE=${VALUE% }
|
||||
|
||||
local FILE="/etc/rspamd/override.d/${MODULE_FILE}"
|
||||
[[ -f ${FILE} ]] || touch "${FILE}"
|
||||
|
||||
if grep -q -E "${OPTION}.*=.*" "${FILE}"
|
||||
then
|
||||
__rspamd__log 'trace' "Overwriting option '${OPTION}' with value '${VALUE}' for ${MODULE_LOG_NAME}"
|
||||
sed -i -E "s|([[:space:]]*${OPTION}).*|\1 = ${VALUE};|g" "${FILE}"
|
||||
else
|
||||
__rspamd__log 'trace' "Setting option '${OPTION}' for ${MODULE_LOG_NAME} to '${VALUE}'"
|
||||
echo "${OPTION} = ${VALUE};" >>"${FILE}"
|
||||
fi
|
||||
}
|
||||
|
||||
local RSPAMD_CUSTOM_COMMANDS_FILE='/tmp/docker-mailserver/rspamd-modules.conf'
|
||||
if [[ -f "${RSPAMD_CUSTOM_COMMANDS_FILE}" ]]
|
||||
then
|
||||
__rspamd__log 'debug' "Found file 'rspamd-modules.conf' - parsing and applying it"
|
||||
|
||||
while read -r COMMAND ARGUMENT1 ARGUMENT2 ARGUMENT3
|
||||
do
|
||||
case "${COMMAND}" in
|
||||
|
||||
('disable-module')
|
||||
__rspamd__enable_disable_module "${ARGUMENT1}" 'false' 'override'
|
||||
;;
|
||||
|
||||
('enable-module')
|
||||
__rspamd__enable_disable_module "${ARGUMENT1}" 'true' 'override'
|
||||
;;
|
||||
|
||||
('set-option-for-module')
|
||||
__add_or_replace "${ARGUMENT1}.conf" "module '${ARGUMENT1}'" "${ARGUMENT2}" "${ARGUMENT3}"
|
||||
;;
|
||||
|
||||
('set-option-for-controller')
|
||||
__add_or_replace 'worker-controller.inc' 'controller worker' "${ARGUMENT1}" "${ARGUMENT2} ${ARGUMENT3}"
|
||||
;;
|
||||
|
||||
('set-option-for-proxy')
|
||||
__add_or_replace 'worker-proxy.inc' 'proxy worker' "${ARGUMENT1}" "${ARGUMENT2} ${ARGUMENT3}"
|
||||
;;
|
||||
|
||||
('set-common-option')
|
||||
__add_or_replace 'options.inc' 'common options' "${ARGUMENT1}" "${ARGUMENT2} ${ARGUMENT3}"
|
||||
;;
|
||||
|
||||
('add-line')
|
||||
__rspamd__log 'trace' "Adding complete line to '${ARGUMENT1}'"
|
||||
echo "${ARGUMENT2} ${ARGUMENT3:-}" >>"/etc/rspamd/override.d/${ARGUMENT1}"
|
||||
;;
|
||||
|
||||
(*)
|
||||
__rspamd__log 'warn' "Command '${COMMAND}' is invalid"
|
||||
continue
|
||||
;;
|
||||
|
||||
esac
|
||||
done < <(_get_valid_lines_from_file "${RSPAMD_CUSTOM_COMMANDS_FILE}")
|
||||
fi
|
||||
}
|
|
@ -99,48 +99,22 @@ function _setup_amavis
|
|||
|
||||
function _setup_rspamd
|
||||
{
|
||||
_log 'warn' 'Rspamd support is under active development, expect breaking changes at any time'
|
||||
|
||||
if [[ ${ENABLE_AMAVIS} -eq 1 ]] || [[ ${ENABLE_SPAMASSASSIN} -eq 1 ]]
|
||||
if [[ -f /usr/local/bin/helpers/setup-rspamd.sh ]]
|
||||
then
|
||||
_log 'warn' 'Running rspamd at the same time as Amavis or SpamAssassin is discouraged'
|
||||
fi
|
||||
|
||||
if [[ ${ENABLE_CLAMAV} -eq 1 ]]
|
||||
then
|
||||
_log 'debug' 'Rspamd will use ClamAV'
|
||||
sedfile -i -E 's|^(enabled).*|\1 = true;|g' /etc/rspamd/local.d/antivirus.conf
|
||||
# RSpamd uses ClamAV's UNIX socket, and to be able to read it, it must be in the same group
|
||||
usermod -a -G clamav _rspamd
|
||||
# ShellCheck sources this from two different files, hence we discard the check of external sources.
|
||||
# shellcheck source=/dev/null
|
||||
source /usr/local/bin/helpers/setup-rspamd.sh
|
||||
else
|
||||
_log 'debug' 'Rspamd will not use ClamAV (which has not been enabled)'
|
||||
_shutdown 'error' '(Rspamd setup) Helper functions required for setup were not found'
|
||||
fi
|
||||
|
||||
declare -a DISABLE_MODULES
|
||||
DISABLE_MODULES=(
|
||||
clickhouse
|
||||
elastic
|
||||
greylist
|
||||
neural
|
||||
reputation
|
||||
spamassassin
|
||||
url_redirector
|
||||
metric_exporter
|
||||
)
|
||||
_log 'warn' 'Rspamd integration is work in progress - expect (breaking) changes at any time'
|
||||
_log 'debug' 'Enabling Rspamd'
|
||||
|
||||
for MODULE in "${DISABLE_MODULES[@]}"
|
||||
do
|
||||
cat >"/etc/rspamd/local.d/${MODULE}.conf" << EOF
|
||||
# documentation: https://rspamd.com/doc/modules/${MODULE}.html
|
||||
|
||||
enabled = false;
|
||||
|
||||
EOF
|
||||
done
|
||||
|
||||
# shellcheck disable=SC2016
|
||||
sed -i -E 's|^(smtpd_milters =.*)|\1 inet:localhost:11332|g' /etc/postfix/main.cf
|
||||
touch /var/lib/rspamd/stats.ucl
|
||||
__rspamd__preflight_checks
|
||||
__rspamd__adjust_postfix_configuration
|
||||
__rspamd__disable_default_modules
|
||||
__rspamd__handle_modules_configuration
|
||||
}
|
||||
|
||||
function _setup_dmarc_hostname
|
||||
|
@ -162,9 +136,7 @@ function _setup_postfix_hostname
|
|||
function _setup_dovecot_hostname
|
||||
{
|
||||
_log 'debug' 'Applying hostname to Dovecot'
|
||||
sed -i \
|
||||
"s|^#hostname =.*$|hostname = '${HOSTNAME}'|g" \
|
||||
/etc/dovecot/conf.d/15-lda.conf
|
||||
sed -i "s|^#hostname =.*$|hostname = '${HOSTNAME}'|g" /etc/dovecot/conf.d/15-lda.conf
|
||||
}
|
||||
|
||||
function _setup_dovecot
|
||||
|
@ -632,6 +604,12 @@ function _setup_SRS
|
|||
postconf 'recipient_canonical_classes = envelope_recipient,header_recipient'
|
||||
}
|
||||
|
||||
# Set up OpenDKIM & OpenDMARC.
|
||||
#
|
||||
# ## Attention
|
||||
#
|
||||
# The OpenDKIM milter must come before the OpenDMARC milter in Postfix's#
|
||||
# `smtpd_milters` milters options.
|
||||
function _setup_dkim_dmarc
|
||||
{
|
||||
if [[ ${ENABLE_OPENDKIM} -eq 1 ]]
|
||||
|
@ -639,45 +617,45 @@ function _setup_dkim_dmarc
|
|||
_log 'debug' 'Setting up DKIM'
|
||||
|
||||
mkdir -p /etc/opendkim/keys/
|
||||
touch /etc/opendkim/SigningTable
|
||||
touch /etc/opendkim/TrustedHosts
|
||||
touch /etc/opendkim/{SigningTable,TrustedHosts,KeyTable}
|
||||
|
||||
_log 'trace' "Adding OpenDKIM to Postfix's milters"
|
||||
postconf 'dkim_milter = inet:localhost:8891'
|
||||
# shellcheck disable=SC2016
|
||||
sed -i -E 's|^(smtpd_milters =.*)|\1 \$dkim_milter|g' /etc/postfix/main.cf
|
||||
# shellcheck disable=SC2016
|
||||
sed -i -E 's|^(non_smtpd_milters =.*)|\1 \$dkim_milter|g' /etc/postfix/main.cf
|
||||
sed -i -E \
|
||||
-e 's|^(smtpd_milters =.*)|\1 \$dkim_milter|g' \
|
||||
-e 's|^(non_smtpd_milters =.*)|\1 \$dkim_milter|g' \
|
||||
/etc/postfix/main.cf
|
||||
|
||||
# check if any keys are available
|
||||
if [[ -e "/tmp/docker-mailserver/opendkim/KeyTable" ]]
|
||||
if [[ -e /tmp/docker-mailserver/opendkim/KeyTable ]]
|
||||
then
|
||||
cp -a /tmp/docker-mailserver/opendkim/* /etc/opendkim/
|
||||
|
||||
local KEYS
|
||||
KEYS=$(find /etc/opendkim/keys/ -type f -maxdepth 1)
|
||||
_log 'trace' "DKIM keys added for: ${KEYS}"
|
||||
_log 'trace' "Changing permissions on '/etc/opendkim'"
|
||||
|
||||
_log 'trace' "DKIM keys added for: $(find /etc/opendkim/keys/ -maxdepth 1 -type f -printf '%f ')"
|
||||
chown -R opendkim:opendkim /etc/opendkim/
|
||||
chmod -R 0700 /etc/opendkim/keys/
|
||||
else
|
||||
_log 'debug' 'No DKIM key(s) provided - check the documentation on how to get your keys'
|
||||
[[ ! -f /etc/opendkim/KeyTable ]] && touch /etc/opendkim/KeyTable
|
||||
_log 'debug' 'OpenDKIM enabled but no DKIM key(s) provided'
|
||||
fi
|
||||
|
||||
# setup nameservers parameter from /etc/resolv.conf if not defined
|
||||
if ! grep '^Nameservers' /etc/opendkim.conf
|
||||
if ! grep -q '^Nameservers' /etc/opendkim.conf
|
||||
then
|
||||
echo "Nameservers $(grep '^nameserver' /etc/resolv.conf | awk -F " " '{print $2}' | paste -sd ',' -)" >>/etc/opendkim.conf
|
||||
|
||||
local NAMESERVER_IPS
|
||||
NAMESERVER_IPS=$(grep '^nameserver' /etc/resolv.conf | awk -F " " '{print $2}' | paste -sd ',' -)
|
||||
echo "Nameservers ${NAMESERVER_IPS}" >>/etc/opendkim.conf
|
||||
_log 'trace' "Nameservers added to '/etc/opendkim.conf'"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${ENABLE_OPENDMARC} -eq 1 ]]
|
||||
then
|
||||
# TODO when disabling SPF is possible, add a check whether DKIM and SPF is disabled
|
||||
# for DMARC to work, you should have at least one enabled
|
||||
# (see RFC 7489 https://www.rfc-editor.org/rfc/rfc7489#page-24)
|
||||
_log 'trace' "Adding OpenDMARC to Postfix's milters"
|
||||
|
||||
postconf 'dmarc_milter = inet:localhost:8893'
|
||||
# Make sure to append the OpenDMARC milter _after_ the OpenDKIM milter!
|
||||
# shellcheck disable=SC2016
|
||||
sed -i -E 's|^(smtpd_milters =.*)|\1 \$dmarc_milter|g' /etc/postfix/main.cf
|
||||
fi
|
||||
|
@ -754,8 +732,8 @@ function _setup_docker_permit
|
|||
_log 'trace' "Adding ${NETWORK_TYPE} (${NETWORK}) to Postfix 'main.cf:mynetworks'"
|
||||
_adjust_mtime_for_postfix_maincf
|
||||
postconf "$(postconf | grep '^mynetworks =') ${NETWORK}"
|
||||
echo "${NETWORK}" >> /etc/opendmarc/ignore.hosts
|
||||
echo "${NETWORK}" >> /etc/opendkim/TrustedHosts
|
||||
[[ ${ENABLE_OPENDMARC} -eq 1 ]] && echo "${NETWORK}" >>/etc/opendmarc/ignore.hosts
|
||||
[[ ${ENABLE_OPENDKIM} -eq 1 ]] && echo "${NETWORK}" >>/etc/opendkim/TrustedHosts
|
||||
}
|
||||
|
||||
case "${PERMIT_DOCKER}" in
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue