mirror of
https://github.com/docker-mailserver/docker-mailserver.git
synced 2024-01-19 02:48:50 +00:00
5f2fb72c9c
* added check for Rspamd DKIM on startup The newly added function `__rspamd__check_dkim_permissions` performs a check on DKIM private key files. This is useful to prevent issues like #3621 in the future. The function is deliberately kept simple and may not catch every single misconfiguration in terms of permissions and ownership, but it should be quite accurate. Please note that the Rspamd setup does NOT change at all, and the checks will not abort the setup in case they fail. A simple warning is emmited. * add more documentation to Rspamd functions * Apply suggestions from code review * improve `__do_as_rspamd_user` * rework check similar to review suggestion see https://github.com/docker-mailserver/docker-mailserver/pull/3627#discussion_r1388697547 --------- Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
285 lines
9.1 KiB
Bash
Executable file
285 lines
9.1 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
# shellcheck source=../scripts/helpers/index.sh
|
|
source /usr/local/bin/helpers/index.sh
|
|
|
|
_trap_err_signal
|
|
|
|
set -u -eE -o pipefail
|
|
shopt -s inherit_errexit
|
|
|
|
# shellcheck source=/dev/null
|
|
source /etc/dms-settings
|
|
|
|
function __usage() {
|
|
_log 'trace' 'Showing usage message now'
|
|
echo -e "${PURPLE}RSPAMD-DKIM${RED}(${YELLOW}8${RED})
|
|
|
|
${ORANGE}NAME${RESET}
|
|
rspamd-dkim - Configure DKIM (DomainKeys Identified Mail)
|
|
|
|
${ORANGE}SYNOPSIS${RESET}
|
|
setup config dkim [ OPTIONS${RED}...${RESET} ]
|
|
|
|
${ORANGE}DESCRIPTION${RESET}
|
|
Creates DKIM keys and configures them within DMS for Rspamd.
|
|
OPTIONS can be used when your requirements are not met by the defaults.
|
|
|
|
${ORANGE}OPTIONS${RESET}
|
|
${BLUE}Generic Program Information${RESET}
|
|
-f | --force Overwrite existing files if there are any
|
|
-v Enable verbose logging (setting the log level to 'debug').
|
|
-vv Enable very verbose logging (setting the log level to 'trace').
|
|
help Print the usage information.
|
|
|
|
${BLUE}Configuration adjustments${RESET}
|
|
keytype Set the type of key you want to use.
|
|
Possible values: rsa, ed25519
|
|
Default: rsa
|
|
keysize Set the size of the keys to be generated.
|
|
Possible values: 1024, 2048 and 4096
|
|
Default: 2048
|
|
Only applies when using keytype=rsa
|
|
selector Set a manual selector for the key.
|
|
Default: mail
|
|
domain Provide the domain for which to generate keys for.
|
|
Default: The FQDN assigned to DMS, excluding any subdomain.
|
|
|
|
${ORANGE}EXAMPLES${RESET}
|
|
${LWHITE}setup config dkim keysize 4096${RESET}
|
|
Creates keys with their length increased to a size of 4096-bit.
|
|
|
|
${LWHITE}setup config dkim keysize 1024 selector 2023-dkim${RESET}
|
|
Creates 1024-bit sized keys, and changes the DKIM selector to '2023-dkim'.
|
|
|
|
${LWHITE}setup config dkim domain example.com${RESET}
|
|
Generate the DKIM key for a different domain (example.com).
|
|
|
|
${ORANGE}EXIT STATUS${RESET}
|
|
Exit status is 0 if command was successful. If wrong arguments are provided or arguments contain
|
|
errors, the script will exit early with a non-zero exit status.
|
|
|
|
"
|
|
}
|
|
|
|
function _parse_arguments() {
|
|
FORCE=0
|
|
KEYTYPE='rsa'
|
|
KEYSIZE='2048'
|
|
SELECTOR='mail'
|
|
DOMAIN=${DOMAINNAME}
|
|
|
|
_log 'trace' "Options given to this script: '${*}'"
|
|
|
|
while [[ ${#} -gt 0 ]]; do
|
|
case "${1}" in
|
|
|
|
( 'keytype' )
|
|
[[ -n ${2:-} ]] || _exit_with_error "No keytype provided after 'keytype' argument"
|
|
if [[ ${2} == 'rsa' ]] || [[ ${2} == 'ed25519' ]]; then
|
|
KEYTYPE=${2}
|
|
_log 'debug' "Keytype set to '${KEYTYPE}'"
|
|
else
|
|
_exit_with_error "Unknown keytype '${2}'"
|
|
fi
|
|
;;
|
|
|
|
( 'keysize' )
|
|
[[ -n ${2:-} ]] || _exit_with_error "No keysize provided after 'keysize' argument"
|
|
KEYSIZE=${2}
|
|
_log 'debug' "Keysize set to '${KEYSIZE}'"
|
|
;;
|
|
|
|
( 'selector' )
|
|
[[ -n ${2:-} ]] || _exit_with_error "No selector provided after 'selector' argument"
|
|
SELECTOR=${2}
|
|
_log 'debug' "Selector set to '${SELECTOR}'"
|
|
;;
|
|
|
|
( 'domain' )
|
|
[[ -n ${2:-} ]] || _exit_with_error "No domain provided after 'domain' argument"
|
|
DOMAIN=${2}
|
|
_log 'debug' "Domain set to '${DOMAIN}'"
|
|
;;
|
|
|
|
( 'help' )
|
|
__usage
|
|
exit 0
|
|
;;
|
|
|
|
( '-f' | '--force' )
|
|
FORCE=1
|
|
shift 1
|
|
continue
|
|
;;
|
|
|
|
( '-vv' )
|
|
# shellcheck disable=SC2034
|
|
LOG_LEVEL='trace'
|
|
shift 1
|
|
_log 'trace' 'Enabled trace-logging'
|
|
continue
|
|
;;
|
|
|
|
( '-v' )
|
|
# shellcheck disable=SC2034
|
|
LOG_LEVEL='debug'
|
|
shift 1
|
|
_log 'debug' 'Enabled debug-logging'
|
|
continue
|
|
;;
|
|
|
|
( * )
|
|
__usage
|
|
_exit_with_error "Unknown option(s) '${1}' ${2:+"and '${2}'"}"
|
|
;;
|
|
esac
|
|
|
|
shift 2
|
|
done
|
|
|
|
return 0
|
|
}
|
|
|
|
function _preflight_checks() {
|
|
if [[ ${KEYTYPE} == 'ed25519' ]] && [[ ${KEYSIZE} -ne 2048 ]]; then
|
|
_exit_with_error "Chosen keytype does not accept the 'keysize' argument"
|
|
fi
|
|
|
|
if [[ ! -d /tmp/docker-mailserver ]]; then
|
|
_log 'warn' "The directory '/tmp/docker-mailserver' does not seem to be mounted by a volume - the Rspamd (DKIM) configuration will not be persisted"
|
|
fi
|
|
|
|
_rspamd_get_envs
|
|
|
|
mkdir -p "${RSPAMD_DMS_DKIM_D}" "${RSPAMD_DMS_OVERRIDE_D}"
|
|
chown _rspamd:_rspamd "${RSPAMD_DMS_DKIM_D}"
|
|
}
|
|
|
|
function _create_keys() {
|
|
if [[ ${KEYTYPE} == 'rsa' ]]; then
|
|
local BASE_FILE_NAME="${RSPAMD_DMS_DKIM_D}/${KEYTYPE}-${KEYSIZE}-${SELECTOR}-${DOMAIN}"
|
|
KEYTYPE_OPTIONS=('-b' "${KEYSIZE}")
|
|
_log 'info' "Creating DKIM keys of type '${KEYTYPE}' and length '${KEYSIZE}' with selector '${SELECTOR}' for domain '${DOMAIN}'"
|
|
else
|
|
local BASE_FILE_NAME="${RSPAMD_DMS_DKIM_D}/${KEYTYPE}-${SELECTOR}-${DOMAIN}"
|
|
KEYTYPE_OPTIONS=('-t' "${KEYTYPE}")
|
|
_log 'info' "Creating DKIM keys of type '${KEYTYPE}' with selector '${SELECTOR}' for domain '${DOMAIN}'"
|
|
fi
|
|
|
|
PUBLIC_KEY_FILE="${BASE_FILE_NAME}.public.txt"
|
|
PUBLIC_KEY_DNS_FILE="${BASE_FILE_NAME}.public.dns.txt"
|
|
PRIVATE_KEY_FILE="${BASE_FILE_NAME}.private.txt"
|
|
|
|
if [[ -f ${PUBLIC_KEY_FILE} ]] || [[ -f ${PUBLIC_KEY_DNS_FILE} ]] || [[ -f ${PRIVATE_KEY_FILE} ]]; then
|
|
if [[ ${FORCE} -eq 0 ]]; then
|
|
_log 'error' "Not overwriting existing files (use '--force' to overwrite existing files)"
|
|
exit 1
|
|
else
|
|
_log 'info' "Overwriting existing files as the '--force' option was supplied"
|
|
rm "${PUBLIC_KEY_FILE}" "${PUBLIC_KEY_DNS_FILE}" "${PRIVATE_KEY_FILE}"
|
|
fi
|
|
fi
|
|
|
|
# shellcheck disable=SC2310
|
|
if __do_as_rspamd_user rspamadm \
|
|
dkim_keygen \
|
|
-s "${SELECTOR}" \
|
|
-d "${DOMAIN}" \
|
|
"${KEYTYPE_OPTIONS[@]}" \
|
|
-k "${PRIVATE_KEY_FILE}" \
|
|
>"${PUBLIC_KEY_FILE}"
|
|
then
|
|
_log 'info' 'Successfully created DKIM keys'
|
|
_log 'debug' "Public key written to '${PUBLIC_KEY_FILE}'"
|
|
_log 'debug' "Private key written to '${PRIVATE_KEY_FILE}'"
|
|
else
|
|
_exit_with_error 'Creating keys failed'
|
|
fi
|
|
}
|
|
|
|
function _check_permissions() {
|
|
# shellcheck disable=SC2310
|
|
if ! __do_as_rspamd_user ls "${RSPAMD_DMS_DKIM_D}" >/dev/null; then
|
|
_log 'warn' "The Rspamd user ('_rspamd') seems to be unable to list files in the keys directory ('${RSPAMD_DMS_DKIM_D}') - Rspamd may experience permission errors later"
|
|
elif ! __do_as_rspamd_user cat "${PRIVATE_KEY_FILE}" >/dev/null; then
|
|
_log 'warn' "The Rspamd user ('_rspamd') seems to be unable to read the private key file - Rspamd may experience permission errors later"
|
|
else
|
|
_log 'debug' 'Permissions on files and directories seem ok'
|
|
fi
|
|
}
|
|
|
|
function _setup_default_signing_conf() {
|
|
local DEFAULT_CONFIG_FILE="${RSPAMD_DMS_OVERRIDE_D}/dkim_signing.conf"
|
|
if [[ -f ${DEFAULT_CONFIG_FILE} ]]; then
|
|
_log 'info' "'${DEFAULT_CONFIG_FILE}' exists, not supplying a default ('--force' does not overwrite this file, manual adjustment required)"
|
|
else
|
|
_log 'info' "Supplying a default configuration (to '${DEFAULT_CONFIG_FILE}')"
|
|
cat >"${DEFAULT_CONFIG_FILE}" << EOF
|
|
# documentation: https://rspamd.com/doc/modules/dkim_signing.html
|
|
|
|
enabled = true;
|
|
|
|
sign_authenticated = true;
|
|
sign_local = false;
|
|
try_fallback = false;
|
|
|
|
use_domain = "header";
|
|
use_redis = false; # don't change unless Redis also provides the DKIM keys
|
|
use_esld = true;
|
|
allow_username_mismatch = true;
|
|
|
|
check_pubkey = true; # you want to use this in the beginning
|
|
|
|
domain {
|
|
${DOMAIN} {
|
|
path = "${PRIVATE_KEY_FILE}";
|
|
selector = "${SELECTOR}";
|
|
}
|
|
}
|
|
|
|
EOF
|
|
|
|
# We copy here immediately in order to not rely on the changedetector - this way, users
|
|
# can immediately use the new keys. The file should not already exist in ${RSPAMD_OVERRIDE_D}
|
|
# since it would have been copied already.
|
|
cp "${DEFAULT_CONFIG_FILE}" "${RSPAMD_OVERRIDE_D}/dkim_signing.conf"
|
|
chown _rspamd:_rspamd "${DEFAULT_CONFIG_FILE}" "${RSPAMD_OVERRIDE_D}/dkim_signing.conf"
|
|
|
|
_log 'debug' 'Restarting Rspamd as initial DKIM configuration was suppplied'
|
|
supervisorctl restart rspamd
|
|
fi
|
|
}
|
|
|
|
function _transform_public_key_file_to_dns_record_contents() {
|
|
_log 'trace' 'Transforming DNS zone format to DNS record content now'
|
|
: >"${PUBLIC_KEY_DNS_FILE}"
|
|
grep -o '".*"' "${PUBLIC_KEY_FILE}" | tr -d '"\n' >>"${PUBLIC_KEY_DNS_FILE}"
|
|
echo '' >>"${PUBLIC_KEY_DNS_FILE}"
|
|
|
|
if ! _log_level_is '(warn|error)'; then
|
|
_log 'info' "Here is the content of the TXT DNS record ${SELECTOR}._domainkey.${DOMAIN} that you need to create:\n"
|
|
cat "${PUBLIC_KEY_DNS_FILE}"
|
|
printf '\n'
|
|
fi
|
|
}
|
|
|
|
function _final_steps() {
|
|
# We need to restart Rspamd so the changes take effect immediately.
|
|
if ! supervisorctl restart rspamd; then
|
|
_log 'warn' 'Could not restart Rspamd via Supervisord'
|
|
fi
|
|
|
|
_log 'trace' 'Finished DKIM key creation'
|
|
}
|
|
|
|
_obtain_hostname_and_domainname
|
|
_require_n_parameters_or_print_usage 0 "${@}"
|
|
_parse_arguments "${@}"
|
|
_preflight_checks
|
|
_create_keys
|
|
_check_permissions
|
|
_setup_default_signing_conf
|
|
_transform_public_key_file_to_dns_record_contents
|
|
_final_steps
|