scripts: housekeeping & cleanup setup (1/2) (#3121)

This commit is contained in:
Georg Lauterbach 2023-02-27 20:21:45 +01:00 committed by GitHub
parent f35b60042f
commit 4b04c3e31c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 233 additions and 262 deletions

View file

@ -1,17 +1,16 @@
#!/bin/bash
# Set up OpenDKIM & OpenDMARC.
# Set up OpenDKIM
#
# ## Attention
#
# The OpenDKIM milter must come before the OpenDMARC milter in Postfix's#
# The OpenDKIM milter must come before the OpenDMARC milter in Postfix's
# `smtpd_milters` milters options.
function _setup_dkim_dmarc
function _setup_opendkim
{
if [[ ${ENABLE_OPENDKIM} -eq 1 ]]
then
_log 'debug' 'Setting up DKIM'
_log 'debug' 'Configuring DKIM'
mkdir -p /etc/opendkim/keys/
touch /etc/opendkim/{SigningTable,TrustedHosts,KeyTable}
@ -43,26 +42,45 @@ function _setup_dkim_dmarc
echo "Nameservers ${NAMESERVER_IPS}" >>/etc/opendkim.conf
_log 'trace' "Nameservers added to '/etc/opendkim.conf'"
fi
else
# Even though we do nothing here and the message suggests we perform some action, the
# message is due to the default value being `1`, i.e. enabled. If the default were `0`,
# we could have said `OpenDKIM is disabled`, but we need to make it uniform with all
# other functions.
_log 'debug' 'Disabling OpenDKIM'
fi
}
# Set up OpenDKIM
#
# ## Attention
#
# The OpenDMARC milter must come after the OpenDKIM milter in Postfix's
# `smtpd_milters` milters options.
function _setup_opendmarc
{
if [[ ${ENABLE_OPENDMARC} -eq 1 ]]
then
# TODO when disabling SPF is possible, add a check whether DKIM and SPF is disabled
# 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 'debug' 'Configuring OpenDMARC'
_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
sed -i \
-e "s|^AuthservID.*$|AuthservID ${HOSTNAME}|g" \
-e "s|^TrustedAuthservIDs.*$|TrustedAuthservIDs ${HOSTNAME}|g" \
/etc/opendmarc.conf
else
# Even though we do nothing here and the message suggests we perform some action, the
# message is due to the default value being `1`, i.e. enabled. If the default were `0`,
# we could have said `OpenDKIM is disabled`, but we need to make it uniform with all
# other functions.
_log 'debug' 'Disabling OpenDMARC'
fi
}
function _setup_dmarc_hostname
{
_log 'debug' 'Setting up DMARC'
sed -i -e \
"s|^AuthservID.*$|AuthservID ${HOSTNAME}|g" \
-e "s|^TrustedAuthservIDs.*$|TrustedAuthservIDs ${HOSTNAME}|g" \
/etc/opendmarc.conf
}

View file

@ -0,0 +1,92 @@
#!/bin/bash
# Consolidate all states into a single directory
# (/var/mail-state) to allow persistence using docker volumes
function _setup_save_states
{
local STATEDIR FILE FILES
STATEDIR='/var/mail-state'
if [[ ${ONE_DIR} -eq 1 ]] && [[ -d ${STATEDIR} ]]
then
_log 'debug' "Consolidating all state onto ${STATEDIR}"
# Always enabled features:
FILES=(
lib/logrotate
lib/postfix
spool/postfix
)
# Only consolidate state for services that are enabled
# Notably avoids copying over 200MB for the ClamAV database
[[ ${ENABLE_AMAVIS} -eq 1 ]] && FILES+=('lib/amavis')
[[ ${ENABLE_CLAMAV} -eq 1 ]] && FILES+=('lib/clamav')
[[ ${ENABLE_FAIL2BAN} -eq 1 ]] && FILES+=('lib/fail2ban')
[[ ${ENABLE_FETCHMAIL} -eq 1 ]] && FILES+=('lib/fetchmail')
[[ ${ENABLE_POSTGREY} -eq 1 ]] && FILES+=('lib/postgrey')
[[ ${ENABLE_RSPAMD} -eq 1 ]] && FILES+=('lib/rspamd')
[[ ${ENABLE_SPAMASSASSIN} -eq 1 ]] && FILES+=('lib/spamassassin')
[[ ${SMTP_ONLY} -ne 1 ]] && FILES+=('lib/dovecot')
for FILE in "${FILES[@]}"
do
DEST="${STATEDIR}/${FILE//\//-}"
FILE="/var/${FILE}"
# If relevant content is found in /var/mail-state (presumably a volume mount),
# use it instead. Otherwise copy over any missing directories checked.
if [[ -d ${DEST} ]]
then
_log 'trace' "Destination ${DEST} exists, linking ${FILE} to it"
# Original content from image no longer relevant, remove it:
rm -rf "${FILE}"
elif [[ -d ${FILE} ]]
then
_log 'trace' "Moving contents of ${FILE} to ${DEST}"
# Empty volume was mounted, or new content from enabling a feature ENV:
mv "${FILE}" "${DEST}"
fi
# Symlink the original path in the container ($FILE) to be
# sourced from assocaiated path in /var/mail-state/ ($DEST):
ln -s "${DEST}" "${FILE}"
done
# This ensures the user and group of the files from the external mount have their
# numeric ID values in sync. New releases where the installed packages order changes
# can change the values in the Docker image, causing an ownership mismatch.
# NOTE: More details about users and groups added during image builds are documented here:
# https://github.com/docker-mailserver/docker-mailserver/pull/3011#issuecomment-1399120252
_log 'trace' 'Fixing /var/mail-state/* permissions'
[[ ${ENABLE_AMAVIS} -eq 1 ]] && chown -R amavis:amavis /var/mail-state/lib-amavis
[[ ${ENABLE_CLAMAV} -eq 1 ]] && chown -R clamav:clamav /var/mail-state/lib-clamav
[[ ${ENABLE_FETCHMAIL} -eq 1 ]] && chown -R fetchmail:nogroup /var/mail-state/lib-fetchmail
[[ ${ENABLE_POSTGREY} -eq 1 ]] && chown -R postgrey:postgrey /var/mail-state/lib-postgrey
[[ ${ENABLE_RSPAMD} -eq 1 ]] && chown -R _rspamd:_rspamd /var/mail-state/lib-rspamd
[[ ${ENABLE_SPAMASSASSIN} -eq 1 ]] && chown -R debian-spamd:debian-spamd /var/mail-state/lib-spamassassin
chown -R root:root /var/mail-state/lib-logrotate
chown -R postfix:postfix /var/mail-state/lib-postfix
# NOTE: The Postfix spool location has mixed owner/groups to take into account:
# UID = postfix(101): active, bounce, corrupt, defer, deferred, flush, hold, incoming, maildrop, private, public, saved, trace
# UID = root(0): dev, etc, lib, pid, usr
# GID = postdrop(103): maildrop, public
# GID for all other directories is root(0)
# NOTE: `spool-postfix/private/` will be set to `postfix:postfix` when Postfix starts / restarts
# Set most common ownership:
chown -R postfix:root /var/mail-state/spool-postfix
chown root:root /var/mail-state/spool-postfix
# These two require the postdrop(103) group:
chgrp -R postdrop /var/mail-state/spool-postfix/maildrop
chgrp -R postdrop /var/mail-state/spool-postfix/public
# These all have root ownership at the src location:
chown -R root /var/mail-state/spool-postfix/dev
chown -R root /var/mail-state/spool-postfix/etc
chown -R root /var/mail-state/spool-postfix/lib
chown -R root /var/mail-state/spool-postfix/pid
chown -R root /var/mail-state/spool-postfix/usr
fi
}

View file

@ -4,18 +4,79 @@ function _setup_security_stack
{
_log 'debug' 'Setting up Security Stack'
__setup__security__postgrey
__setup__security__postscreen
# recreate auto-generated file
local DMS_AMAVIS_FILE=/etc/amavis/conf.d/61-dms_auto_generated
echo "# WARNING: this file is auto-generated." >"${DMS_AMAVIS_FILE}"
echo "use strict;" >>"${DMS_AMAVIS_FILE}"
# SpamAssassin
if [[ ${ENABLE_SPAMASSASSIN} -eq 0 ]]
__setup__security__spamassassin
__setup__security__clamav
echo '1; # ensure a defined return' >>"${DMS_AMAVIS_FILE}"
chmod 444 "${DMS_AMAVIS_FILE}"
__setup__security__fail2ban
__setup__security__amavis
}
function __setup__security__postgrey
{
if [[ ${ENABLE_POSTGREY} -eq 1 ]]
then
_log 'debug' 'SpamAssassin is disabled'
echo "@bypass_spam_checks_maps = (1);" >>"${DMS_AMAVIS_FILE}"
elif [[ ${ENABLE_SPAMASSASSIN} -eq 1 ]]
_log 'debug' 'Enabling and configuring Postgrey'
sedfile -i -E \
's|(^smtpd_recipient_restrictions =.*)|\1, check_policy_service inet:127.0.0.1:10023|' \
/etc/postfix/main.cf
sed -i -e \
"s|\"--inet=127.0.0.1:10023\"|\"--inet=127.0.0.1:10023 --delay=${POSTGREY_DELAY} --max-age=${POSTGREY_MAX_AGE} --auto-whitelist-clients=${POSTGREY_AUTO_WHITELIST_CLIENTS}\"|" \
/etc/default/postgrey
if ! grep -i 'POSTGREY_TEXT' /etc/default/postgrey
then
printf 'POSTGREY_TEXT=\"%s\"\n\n' "${POSTGREY_TEXT}" >>/etc/default/postgrey
fi
if [[ -f /tmp/docker-mailserver/whitelist_clients.local ]]
then
cp -f /tmp/docker-mailserver/whitelist_clients.local /etc/postgrey/whitelist_clients.local
fi
if [[ -f /tmp/docker-mailserver/whitelist_recipients ]]
then
cp -f /tmp/docker-mailserver/whitelist_recipients /etc/postgrey/whitelist_recipients
fi
else
_log 'debug' 'Postscreen is disabled'
fi
}
function __setup__security__postscreen
{
_log 'debug' 'Configuring Postscreen'
sed -i \
-e "s|postscreen_dnsbl_action = enforce|postscreen_dnsbl_action = ${POSTSCREEN_ACTION}|" \
-e "s|postscreen_greet_action = enforce|postscreen_greet_action = ${POSTSCREEN_ACTION}|" \
-e "s|postscreen_bare_newline_action = enforce|postscreen_bare_newline_action = ${POSTSCREEN_ACTION}|" /etc/postfix/main.cf
if [[ ${ENABLE_DNSBL} -eq 0 ]]
then
_log 'debug' 'Disabling Postscreen DNSBLs'
postconf 'postscreen_dnsbl_action = ignore'
postconf 'postscreen_dnsbl_sites = '
else
_log 'debug' 'Postscreen DNSBLs are enabled'
fi
}
function __setup__security__spamassassin
{
if [[ ${ENABLE_SPAMASSASSIN} -eq 1 ]]
then
_log 'debug' 'Enabling and configuring SpamAssassin'
@ -28,6 +89,11 @@ function _setup_security_stack
# shellcheck disable=SC2016
sed -i -r 's|^\$sa_kill_level_deflt (.*);|\$sa_kill_level_deflt = '"${SA_KILL}"';|g' /etc/amavis/conf.d/20-debian_defaults
# fix cron.daily for spamassassin
sed -i \
's|invoke-rc.d spamassassin reload|/etc/init\.d/spamassassin reload|g' \
/etc/cron.daily/spamassassin
if [[ ${SA_SPAM_SUBJECT} == 'undef' ]]
then
# shellcheck disable=SC2016
@ -96,25 +162,37 @@ EOF
chmod +x "${SPAMASSASSIN_KAM_CRON_FILE}"
fi
else
_log 'debug' 'SpamAssassin is disabled'
echo "@bypass_spam_checks_maps = (1);" >>"${DMS_AMAVIS_FILE}"
rm -f /etc/cron.daily/spamassassin
fi
}
# ClamAV
if [[ ${ENABLE_CLAMAV} -eq 0 ]]
function __setup__security__clamav
{
if [[ ${ENABLE_CLAMAV} -eq 1 ]]
then
_log 'debug' 'ClamAV is disabled'
_log 'debug' 'Enabling and configuring ClamAV'
if [[ ${CLAMAV_MESSAGE_SIZE_LIMIT} != '25M' ]]
then
_log 'trace' "Setting ClamAV message scan size limit to '${CLAMAV_MESSAGE_SIZE_LIMIT}'"
sedfile -i \
"s/^MaxFileSize.*/MaxFileSize ${CLAMAV_MESSAGE_SIZE_LIMIT}/" \
/etc/clamav/clamd.conf
fi
else
_log 'debug' 'Disabling ClamAV'
echo '@bypass_virus_checks_maps = (1);' >>"${DMS_AMAVIS_FILE}"
elif [[ ${ENABLE_CLAMAV} -eq 1 ]]
then
_log 'debug' 'Enabling ClamAV'
rm -f /etc/logrotate.d/clamav-* /etc/cron.d/clamav-freshclam
fi
}
echo '1; # ensure a defined return' >>"${DMS_AMAVIS_FILE}"
chmod 444 "${DMS_AMAVIS_FILE}"
# Fail2ban
function __setup__security__fail2ban
{
if [[ ${ENABLE_FAIL2BAN} -eq 1 ]]
then
_log 'debug' 'Enabling Fail2Ban'
_log 'debug' 'Enabling and configuring Fail2Ban'
if [[ -e /tmp/docker-mailserver/fail2ban-fail2ban.cf ]]
then
@ -125,20 +203,24 @@ EOF
then
cp /tmp/docker-mailserver/fail2ban-jail.cf /etc/fail2ban/jail.d/user-jail.local
fi
if [[ ${FAIL2BAN_BLOCKTYPE} != 'reject' ]]
then
echo -e '[Init]\nblocktype = drop' >/etc/fail2ban/action.d/nftables-common.local
fi
echo '[Definition]' >/etc/fail2ban/filter.d/custom.conf
else
# disable logrotate config for fail2ban if not enabled
_log 'debug' 'Fail2Ban is disabled'
rm -f /etc/logrotate.d/fail2ban
fi
}
# fix cron.daily for spamassassin
sed -i \
's|invoke-rc.d spamassassin reload|/etc/init\.d/spamassassin reload|g' \
/etc/cron.daily/spamassassin
# Amavis
function __setup__security__amavis
{
if [[ ${ENABLE_AMAVIS} -eq 1 ]]
then
_log 'debug' 'Enabling Amavis'
_log 'debug' 'Configuring Amavis'
if [[ -f /tmp/docker-mailserver/amavis.cf ]]
then
cp /tmp/docker-mailserver/amavis.cf /etc/amavis/conf.d/50-user
@ -147,14 +229,6 @@ EOF
sed -i -E \
"s|(log_level).*|\1 = ${AMAVIS_LOGLEVEL};|g" \
/etc/amavis/conf.d/49-docker-mailserver
fi
}
function _setup_amavis
{
if [[ ${ENABLE_AMAVIS} -eq 1 ]]
then
_log 'debug' 'Setting up Amavis'
cat /etc/dms/postfix/master.d/postfix-amavis.cf >>/etc/postfix/master.cf
postconf 'content_filter = smtp-amavis:[127.0.0.1]:10024'
@ -163,7 +237,9 @@ function _setup_amavis
"s|^#\$myhostname = \"mail.example.com\";|\$myhostname = \"${HOSTNAME}\";|" \
/etc/amavis/conf.d/05-node_id
else
_log 'debug' 'Disabling Amavis cron job'
_log 'debug' 'Disabling Amavis'
_log 'trace' 'Disabling Amavis cron job'
mv /etc/cron.d/amavisd-new /etc/cron.d/amavisd-new.disabled
chmod 0 /etc/cron.d/amavisd-new.disabled
@ -178,88 +254,3 @@ function _setup_amavis
fi
fi
}
function _setup_fail2ban
{
_log 'debug' 'Setting up Fail2Ban'
if [[ ${FAIL2BAN_BLOCKTYPE} != 'reject' ]]
then
echo -e '[Init]\nblocktype = drop' >/etc/fail2ban/action.d/nftables-common.local
fi
echo '[Definition]' >/etc/fail2ban/filter.d/custom.conf
}
function _setup_postgrey
{
_log 'debug' 'Configuring Postgrey'
sedfile -i -E \
's|(^smtpd_recipient_restrictions =.*)|\1, check_policy_service inet:127.0.0.1:10023|' \
/etc/postfix/main.cf
sed -i -e \
"s|\"--inet=127.0.0.1:10023\"|\"--inet=127.0.0.1:10023 --delay=${POSTGREY_DELAY} --max-age=${POSTGREY_MAX_AGE} --auto-whitelist-clients=${POSTGREY_AUTO_WHITELIST_CLIENTS}\"|" \
/etc/default/postgrey
TEXT_FOUND=$(grep -c -i 'POSTGREY_TEXT' /etc/default/postgrey)
if [[ ${TEXT_FOUND} -eq 0 ]]
then
printf 'POSTGREY_TEXT=\"%s\"\n\n' "${POSTGREY_TEXT}" >>/etc/default/postgrey
fi
if [[ -f /tmp/docker-mailserver/whitelist_clients.local ]]
then
cp -f /tmp/docker-mailserver/whitelist_clients.local /etc/postgrey/whitelist_clients.local
fi
if [[ -f /tmp/docker-mailserver/whitelist_recipients ]]
then
cp -f /tmp/docker-mailserver/whitelist_recipients /etc/postgrey/whitelist_recipients
fi
}
function _setup_postfix_postscreen
{
_log 'debug' 'Configuring Postscreen'
sed -i \
-e "s|postscreen_dnsbl_action = enforce|postscreen_dnsbl_action = ${POSTSCREEN_ACTION}|" \
-e "s|postscreen_greet_action = enforce|postscreen_greet_action = ${POSTSCREEN_ACTION}|" \
-e "s|postscreen_bare_newline_action = enforce|postscreen_bare_newline_action = ${POSTSCREEN_ACTION}|" /etc/postfix/main.cf
}
function _setup_clamav_sizelimit
{
_log 'trace' "Setting ClamAV message scan size limit to '${CLAMAV_MESSAGE_SIZE_LIMIT}'"
sedfile -i "s/^MaxFileSize.*/MaxFileSize ${CLAMAV_MESSAGE_SIZE_LIMIT}/" /etc/clamav/clamd.conf
}
function _setup_spoof_protection
{
_log 'trace' 'Configuring spoof protection'
sed -i \
's|smtpd_sender_restrictions =|smtpd_sender_restrictions = reject_authenticated_sender_login_mismatch,|' \
/etc/postfix/main.cf
if [[ ${ACCOUNT_PROVISIONER} == 'LDAP' ]]
then
if [[ -z ${LDAP_QUERY_FILTER_SENDERS} ]]
then
postconf 'smtpd_sender_login_maps = ldap:/etc/postfix/ldap-users.cf ldap:/etc/postfix/ldap-aliases.cf ldap:/etc/postfix/ldap-groups.cf'
else
postconf 'smtpd_sender_login_maps = ldap:/etc/postfix/ldap-senders.cf'
fi
else
if [[ -f /etc/postfix/regexp ]]
then
postconf 'smtpd_sender_login_maps = unionmap:{ texthash:/etc/postfix/virtual, hash:/etc/aliases, pcre:/etc/postfix/maps/sender_login_maps.pcre, pcre:/etc/postfix/regexp }'
else
postconf 'smtpd_sender_login_maps = texthash:/etc/postfix/virtual, hash:/etc/aliases, pcre:/etc/postfix/maps/sender_login_maps.pcre'
fi
fi
}

View file

@ -2,13 +2,18 @@
function _setup_rspamd
{
_log 'warn' 'Rspamd integration is work in progress - expect (breaking) changes at any time'
_log 'debug' 'Enabling Rspamd'
if [[ ${ENABLE_RSPAMD} -eq 1 ]]
then
_log 'warn' 'Rspamd integration is work in progress - expect (breaking) changes at any time'
_log 'debug' 'Enabling and configuring Rspamd'
__rspamd__preflight_checks
__rspamd__adjust_postfix_configuration
__rspamd__disable_default_modules
__rspamd__handle_modules_configuration
__rspamd__preflight_checks
__rspamd__adjust_postfix_configuration
__rspamd__disable_default_modules
__rspamd__handle_modules_configuration
else
_log 'debug' 'Rspamd is disabled'
fi
}
# Just a helper to prepend the log messages with `(Rspamd setup)` so

View file

@ -0,0 +1,32 @@
#!/bin/bash
function _setup_spoof_protection
{
if [[ ${SPOOF_PROTECTION} -eq 1 ]]
then
_log 'trace' 'Enabling and configuring spoof protection'
sed -i \
's|smtpd_sender_restrictions =|smtpd_sender_restrictions = reject_authenticated_sender_login_mismatch,|' \
/etc/postfix/main.cf
if [[ ${ACCOUNT_PROVISIONER} == 'LDAP' ]]
then
if [[ -z ${LDAP_QUERY_FILTER_SENDERS} ]]
then
postconf 'smtpd_sender_login_maps = ldap:/etc/postfix/ldap-users.cf ldap:/etc/postfix/ldap-aliases.cf ldap:/etc/postfix/ldap-groups.cf'
else
postconf 'smtpd_sender_login_maps = ldap:/etc/postfix/ldap-senders.cf'
fi
else
if [[ -f /etc/postfix/regexp ]]
then
postconf 'smtpd_sender_login_maps = unionmap:{ texthash:/etc/postfix/virtual, hash:/etc/aliases, pcre:/etc/postfix/maps/sender_login_maps.pcre, pcre:/etc/postfix/regexp }'
else
postconf 'smtpd_sender_login_maps = texthash:/etc/postfix/virtual, hash:/etc/aliases, pcre:/etc/postfix/maps/sender_login_maps.pcre'
fi
fi
else
_log 'debug' 'Spoof protection is disabled'
fi
}