diff --git a/Dockerfile b/Dockerfile index 752fb501..86626cac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -108,7 +108,7 @@ RUN \ rm -rf /var/log/clamav/ # ----------------------------------------------- -# --- Dovecot & MkCert -------------------------- +# --- Dovecot ----------------------------------- # ----------------------------------------------- COPY target/dovecot/auth-passwdfile.inc target/dovecot/??-*.conf /etc/dovecot/conf.d/ @@ -124,10 +124,6 @@ RUN \ sedfile -i -e 's/^.*lda_mailbox_autocreate.*/lda_mailbox_autocreate = yes/g' /etc/dovecot/conf.d/15-lda.conf && \ sedfile -i -e 's/^.*lda_mailbox_autosubscribe.*/lda_mailbox_autosubscribe = yes/g' /etc/dovecot/conf.d/15-lda.conf && \ sedfile -i -e 's/^.*postmaster_address.*/postmaster_address = '${POSTMASTER_ADDRESS:="postmaster@domain.com"}'/g' /etc/dovecot/conf.d/15-lda.conf && \ - sedfile -i 's/RANDFILE.*//g' /usr/share/dovecot/dovecot-openssl.cnf && \ - mkdir /etc/dovecot/ssl && \ - chmod 755 /etc/dovecot/ssl && \ - ./mkcert.sh 2>&1 && \ mkdir -p /usr/lib/dovecot/sieve-pipe /usr/lib/dovecot/sieve-filter /usr/lib/dovecot/sieve-global && \ chmod 755 -R /usr/lib/dovecot/sieve-pipe /usr/lib/dovecot/sieve-filter /usr/lib/dovecot/sieve-global @@ -241,8 +237,7 @@ COPY \ RUN \ : >/etc/aliases && \ sedfile -i 's/START_DAEMON=no/START_DAEMON=yes/g' /etc/default/fetchmail && \ - mkdir /var/run/fetchmail && chown fetchmail /var/run/fetchmail && \ - curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem >/etc/ssl/certs/lets-encrypt-x3-cross-signed.pem + mkdir /var/run/fetchmail && chown fetchmail /var/run/fetchmail # ----------------------------------------------- # --- Logs -------------------------------------- diff --git a/target/dovecot/10-ssl.conf b/target/dovecot/10-ssl.conf index 4ae324bb..c52d21f5 100644 --- a/target/dovecot/10-ssl.conf +++ b/target/dovecot/10-ssl.conf @@ -6,11 +6,12 @@ #ssl = yes # PEM encoded X.509 SSL/TLS certificate and private key. They're opened before -# dropping root privileges, so keep the key file unreadable by anyone but -# root. Included doc/mkcert.sh can be used to easily generate self-signed -# certificate, just make sure to update the domains in dovecot-openssl.cnf -ssl_cert = (Internal value for matching). You should use the convenience methods below based on your panic type. +# PANIC_INFO => Provide your own message string to insert into the error message for that PANIC_TYPE. +# PANIC_SCOPE => Optionally provide a string for debugging to better identify/locate the source of the panic. +function dms_panic +{ + local PANIC_TYPE=$1 + local PANIC_INFO=$2 + local PANIC_SCOPE=$3 #optional + + local SHUTDOWN_MESSAGE + + case "${PANIC_TYPE}" in + ( 'no-env' ) # PANIC_INFO == + SHUTDOWN_MESSAGE="Environment Variable: ${PANIC_INFO} is not set!" + ;; + + ( 'no-file' ) # PANIC_INFO == + SHUTDOWN_MESSAGE="File ${PANIC_INFO} does not exist!" + ;; + + ( 'misconfigured' ) # PANIC_INFO == + SHUTDOWN_MESSAGE="${PANIC_INFO} appears to be misconfigured, please verify." + ;; + + ( 'invalid-value' ) # PANIC_INFO == + SHUTDOWN_MESSAGE="Invalid value for ${PANIC_INFO}!" + ;; + + ( * ) # `dms_panic` was called directly without a valid PANIC_TYPE + SHUTDOWN_MESSAGE='Something broke :(' + ;; + esac + + if [[ -n ${PANIC_SCOPE} ]] + then + _shutdown "${PANIC_SCOPE} | ${SHUTDOWN_MESSAGE}" + else + _shutdown "${SHUTDOWN_MESSAGE}" + fi +} + +# Convenience wrappers based on type: +function dms_panic__no_env { dms_panic 'no-env' "${1}" "${2}"; } +function dms_panic__no_file { dms_panic 'no-file' "${1}" "${2}"; } +function dms_panic__misconfigured { dms_panic 'misconfigured' "${1}" "${2}"; } +function dms_panic__invalid_value { dms_panic 'invalid-value' "${1}" "${2}"; } + function escape { echo "${1//./\\.}" @@ -252,8 +303,13 @@ function _obtain_hostname_and_domainname fi } +# Call this method when you want to panic (emit a 'FATAL' log level error, and exit uncleanly). +# `dms_panic` methods should be preferred if your failure type is supported. function _shutdown { + local FATAL_ERROR_MESSAGE=$1 + + _notify 'fatal' "${FATAL_ERROR_MESSAGE}" _notify 'err' "Shutting down.." kill 1 } diff --git a/target/scripts/startup/check-stack.sh b/target/scripts/startup/check-stack.sh index f7061d35..6c731eb3 100644 --- a/target/scripts/startup/check-stack.sh +++ b/target/scripts/startup/check-stack.sh @@ -16,10 +16,10 @@ function _check_hostname _notify 'inf' "Domain has been set to ${DOMAINNAME}" _notify 'inf' "Hostname has been set to ${HOSTNAME}" + # HOSTNAME should be an FQDN (eg: hostname.domain) if ! grep -q -E '^(\S+[.]\S+)$' <<< "${HOSTNAME}" then - _notify 'err' 'Setting hostname/domainname is required' - _shutdown + _shutdown 'Setting hostname/domainname is required' return 1 fi } diff --git a/target/scripts/startup/setup-stack.sh b/target/scripts/startup/setup-stack.sh index 8f4f00b6..300ce5fb 100644 --- a/target/scripts/startup/setup-stack.sh +++ b/target/scripts/startup/setup-stack.sh @@ -168,27 +168,6 @@ function _setup_dovecot { _notify 'task' 'Setting up Dovecot' - # moved from docker file, copy or generate default self-signed cert - if [[ -f /var/mail-state/lib-dovecot/dovecot.pem ]] && [[ ${ONE_DIR} -eq 1 ]] - then - _notify 'inf' "Copying default dovecot cert" - cp /var/mail-state/lib-dovecot/dovecot.key /etc/dovecot/ssl/ - cp /var/mail-state/lib-dovecot/dovecot.pem /etc/dovecot/ssl/ - fi - - if [[ ! -f /etc/dovecot/ssl/dovecot.pem ]] - then - _notify 'inf' 'Generating default Dovecot cert' - /usr/share/dovecot/mkcert.sh - - if [[ ${ONE_DIR} -eq 1 ]] - then - mkdir -p /var/mail-state/lib-dovecot - cp /etc/dovecot/ssl/dovecot.key /var/mail-state/lib-dovecot/ - cp /etc/dovecot/ssl/dovecot.pem /var/mail-state/lib-dovecot/ - fi - fi - cp -a /usr/share/dovecot/protocols.d /etc/dovecot/ # disable pop3 (it will be eventually enabled later in the script, if requested) mv /etc/dovecot/protocols.d/pop3d.protocol /etc/dovecot/protocols.d/pop3d.protocol.disab @@ -803,8 +782,13 @@ function _setup_ssl _notify 'task' 'Setting up SSL' local POSTFIX_CONFIG_MAIN='/etc/postfix/main.cf' + local POSTFIX_CONFIG_MASTER='/etc/postfix/master.cf' local DOVECOT_CONFIG_SSL='/etc/dovecot/conf.d/10-ssl.conf' + local TMP_DMS_TLS_PATH='/tmp/docker-mailserver/ssl' # config volume + local DMS_TLS_PATH='/etc/dms/tls' + mkdir -p "${DMS_TLS_PATH}" + # Primary certificate to serve for TLS function _set_certificate { @@ -812,7 +796,7 @@ function _setup_ssl local DOVECOT_KEY=${1} local DOVECOT_CERT=${1} - # If 2nd param is provided, we've been provided separate key and cert instead of a fullkeychain + # If a 2nd param is provided, a separate key and cert was received instead of a fullkeychain if [[ -n ${2} ]] then local PRIVATE_KEY=$1 @@ -825,12 +809,14 @@ function _setup_ssl # Postfix configuration # NOTE: `smtpd_tls_chain_files` expects private key defined before public cert chain - # May be a single PEM file or a sequence of files, so long as the order is key->leaf->chain - sed -i "s|^smtpd_tls_chain_files =.*|smtpd_tls_chain_files = ${POSTFIX_KEY_WITH_FULLCHAIN}|" "${POSTFIX_CONFIG_MAIN}" + # Value can be a single PEM file, or a sequence of files; so long as the order is key->leaf->chain + sedfile -i -r "s|^(smtpd_tls_chain_files =).*|\1 ${POSTFIX_KEY_WITH_FULLCHAIN}|" "${POSTFIX_CONFIG_MAIN}" # Dovecot configuration - sed -i "s|^ssl_key = <.*|ssl_key = <${DOVECOT_KEY}|" "${DOVECOT_CONFIG_SSL}" - sed -i "s|^ssl_cert = <.*|ssl_cert = <${DOVECOT_CERT}|" "${DOVECOT_CONFIG_SSL}" + sedfile -i -r \ + -e "s|^(ssl_key =).*|\1 <${DOVECOT_KEY}|" \ + -e "s|^(ssl_cert =).*|\1 <${DOVECOT_CERT}|" \ + "${DOVECOT_CONFIG_SSL}" } # Enables supporting two certificate types such as ECDSA with an RSA fallback @@ -838,26 +824,28 @@ function _setup_ssl { local COPY_KEY_FROM_PATH=$1 local COPY_CERT_FROM_PATH=$2 - local PRIVATE_KEY_ALT='/etc/postfix/ssl/fallback_key' - local CERT_CHAIN_ALT='/etc/postfix/ssl/fallback_cert' + local PRIVATE_KEY_ALT="${DMS_TLS_PATH}/fallback_key" + local CERT_CHAIN_ALT="${DMS_TLS_PATH}/fallback_cert" cp "${COPY_KEY_FROM_PATH}" "${PRIVATE_KEY_ALT}" cp "${COPY_CERT_FROM_PATH}" "${CERT_CHAIN_ALT}" chmod 600 "${PRIVATE_KEY_ALT}" - chmod 600 "${CERT_CHAIN_ALT}" + chmod 644 "${CERT_CHAIN_ALT}" # Postfix configuration # NOTE: This operation doesn't replace the line, it appends to the end of the line. # Thus this method should only be used when this line has explicitly been replaced earlier in the script. # Otherwise without `docker-compose down` first, a `docker-compose up` may # persist previous container state and cause a failure in postfix configuration. - sed -i "s|^smtpd_tls_chain_files =.*|& ${PRIVATE_KEY_ALT} ${CERT_CHAIN_ALT}|" "${POSTFIX_CONFIG_MAIN}" + sedfile -i "s|^smtpd_tls_chain_files =.*|& ${PRIVATE_KEY_ALT} ${CERT_CHAIN_ALT}|" "${POSTFIX_CONFIG_MAIN}" # Dovecot configuration # Conditionally checks for `#`, in the event that internal container state is accidentally persisted, # can be caused by: `docker-compose up` run again after a `ctrl+c`, without running `docker-compose down` - sed -i "s|^#\?ssl_alt_key = <.*|ssl_alt_key = <${PRIVATE_KEY_ALT}|" "${DOVECOT_CONFIG_SSL}" - sed -i "s|^#\?ssl_alt_cert = <.*|ssl_alt_cert = <${CERT_CHAIN_ALT}|" "${DOVECOT_CONFIG_SSL}" + sedfile -i -r \ + -e "s|^#?(ssl_alt_key =).*|\1 <${PRIVATE_KEY_ALT}|" \ + -e "s|^#?(ssl_alt_cert =).*|\1 <${CERT_CHAIN_ALT}|" \ + "${DOVECOT_CONFIG_SSL}" } function _apply_tls_level @@ -867,19 +855,22 @@ function _setup_ssl local TLS_PROTOCOL_MINIMUM=$3 # Postfix configuration - sed -i "s|^smtpd_tls_mandatory_protocols =.*|smtpd_tls_mandatory_protocols = ${TLS_PROTOCOL_IGNORE}|" "${POSTFIX_CONFIG_MAIN}" - sed -i "s|^smtpd_tls_protocols =.*|smtpd_tls_protocols = ${TLS_PROTOCOL_IGNORE}|" "${POSTFIX_CONFIG_MAIN}" - sed -i "s|^smtp_tls_protocols =.*|smtp_tls_protocols = ${TLS_PROTOCOL_IGNORE}|" "${POSTFIX_CONFIG_MAIN}" - sed -i "s|^tls_high_cipherlist =.*|tls_high_cipherlist = ${TLS_CIPHERS_ALLOW}|" "${POSTFIX_CONFIG_MAIN}" + sed -i -r \ + -e "s|^(smtpd?_tls_mandatory_protocols =).*|\1 ${TLS_PROTOCOL_IGNORE}|" \ + -e "s|^(smtpd?_tls_protocols =).*|\1 ${TLS_PROTOCOL_IGNORE}|" \ + -e "s|^(tls_high_cipherlist =).*|\1 ${TLS_CIPHERS_ALLOW}|" \ + "${POSTFIX_CONFIG_MAIN}" # Dovecot configuration (secure by default though) - sed -i "s|^ssl_min_protocol =.*|ssl_min_protocol = ${TLS_PROTOCOL_MINIMUM}|" "${DOVECOT_CONFIG_SSL}" - sed -i "s|^ssl_cipher_list =.*|ssl_cipher_list = ${TLS_CIPHERS_ALLOW}|" "${DOVECOT_CONFIG_SSL}" + sed -i -r \ + -e "s|^(ssl_min_protocol =).*|\1 ${TLS_PROTOCOL_MINIMUM}|" \ + -e "s|^(ssl_cipher_list =).*|\1 ${TLS_CIPHERS_ALLOW}|" \ + "${DOVECOT_CONFIG_SSL}" } # TLS strength/level configuration case "${TLS_LEVEL}" in - "modern" ) + ( "modern" ) local TLS_MODERN_SUITE='ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384' local TLS_MODERN_IGNORE='!SSLv2,!SSLv3,!TLSv1,!TLSv1.1' local TLS_MODERN_MIN='TLSv1.2' @@ -889,36 +880,42 @@ function _setup_ssl _notify 'inf' "TLS configured with 'modern' ciphers" ;; - "intermediate" ) + ( "intermediate" ) local TLS_INTERMEDIATE_SUITE='ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA' local TLS_INTERMEDIATE_IGNORE='!SSLv2,!SSLv3' local TLS_INTERMEDIATE_MIN='TLSv1' _apply_tls_level "${TLS_INTERMEDIATE_SUITE}" "${TLS_INTERMEDIATE_IGNORE}" "${TLS_INTERMEDIATE_MIN}" - # Lowers the minimum acceptable TLS version connection to `TLS 1.0` (from Debian upstream `TLS 1.2`) - # Lowers Security Level to `1` (from Debian upstream `2`) + # Lowers the minimum acceptable TLS version connection to `TLSv1` (from Debian upstream `TLSv1.2`) + # Lowers Security Level to `1` (from Debian upstream `2`, openssl release defaults to `1`) + # https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_security_level.html # https://wiki.debian.org/ContinuousIntegration/TriagingTips/openssl-1.1.1 # https://dovecot.org/pipermail/dovecot/2020-October/120225.html - # TODO: This is a fix for Debian Bullseye Dovecot. Deprecate TLS <1.2 to resolve properly. - sedfile -i 's|^MinProtocol = .*|MinProtocol = TLSv1|' /usr/lib/ssl/openssl.cnf - sedfile -i 's|^CipherString = .*|CipherString = DEFAULT@SECLEVEL=1|' /usr/lib/ssl/openssl.cnf + # TODO: This is a fix for Debian Bullseye Dovecot. Can remove when we only support TLS >=1.2. + # WARNING: This applies to all processes that use openssl and respect these settings. + sedfile -i -r \ + -e 's|^(MinProtocol).*|\1 = TLSv1|' \ + -e 's|^(CipherString).*|\1 = DEFAULT@SECLEVEL=1|' \ + /usr/lib/ssl/openssl.cnf _notify 'inf' "TLS configured with 'intermediate' ciphers" ;; - * ) + ( * ) _notify 'err' "TLS_LEVEL not found [ in ${FUNCNAME[0]} ]" ;; esac + local SCOPE_SSL_TYPE="TLS Setup [SSL_TYPE=${SSL_TYPE}]" # SSL certificate Configuration # TODO: Refactor this feature, it's been extended multiple times for specific inputs/providers unnecessarily. - # NOTE: Some `SSL_TYPE` logic uses mounted certs/keys directly, some make an internal copy either retaining filename or renaming, chmod inconsistent. + # NOTE: Some `SSL_TYPE` logic uses mounted certs/keys directly, some make an internal copy either retaining filename or renaming. case "${SSL_TYPE}" in - "letsencrypt" ) + ( "letsencrypt" ) _notify 'inf' "Configuring SSL using 'letsencrypt'" + # letsencrypt folders and files mounted in /etc/letsencrypt local LETSENCRYPT_DOMAIN="" local LETSENCRYPT_KEY="" @@ -982,104 +979,179 @@ function _setup_ssl fi return 0 ;; - "custom" ) - # Adding CA signed SSL certificate if provided in 'postfix/ssl' folder - if [[ -e /tmp/docker-mailserver/ssl/${HOSTNAME}-full.pem ]] + + ( "custom" ) # (hard-coded path) Use a private key with full certificate chain all in a single PEM file. + _notify 'inf' "Adding ${HOSTNAME} SSL certificate" + + # NOTE: Dovecot works fine still as both values are bundled into the keychain + local COMBINED_PEM_NAME="${HOSTNAME}-full.pem" + local TMP_KEY_WITH_FULLCHAIN="${TMP_DMS_TLS_PATH}/${COMBINED_PEM_NAME}" + local KEY_WITH_FULLCHAIN="${DMS_TLS_PATH}/${COMBINED_PEM_NAME}" + + if [[ -f ${TMP_KEY_WITH_FULLCHAIN} ]] then - _notify 'inf' "Adding ${HOSTNAME} SSL certificate" - - mkdir -p /etc/postfix/ssl - cp "/tmp/docker-mailserver/ssl/${HOSTNAME}-full.pem" /etc/postfix/ssl - - # Private key with full certificate chain all in a single PEM file - # NOTE: Dovecot works fine still as both values are bundled into the keychain - local KEY_WITH_FULLCHAIN='/etc/postfix/ssl/'"${HOSTNAME}"'-full.pem' + cp "${TMP_KEY_WITH_FULLCHAIN}" "${KEY_WITH_FULLCHAIN}" + chmod 600 "${KEY_WITH_FULLCHAIN}" _set_certificate "${KEY_WITH_FULLCHAIN}" _notify 'inf' "SSL configured with 'CA signed/custom' certificates" + else + dms_panic__no_file "${TMP_KEY_WITH_FULLCHAIN}" "${SCOPE_SSL_TYPE}" fi ;; - "manual" ) - # Lets you manually specify the location of the SSL Certs to use. This gives you some more control over this whole processes (like using kube-lego to generate certs) - if [[ -n ${SSL_CERT_PATH} ]] && [[ -n ${SSL_KEY_PATH} ]] + + ( "manual" ) # (dynamic path via ENV) Use separate private key and cert/chain files (should be PEM encoded) + _notify 'inf' "Configuring certificates using key ${SSL_KEY_PATH} and cert ${SSL_CERT_PATH}" + + # Source files are copied internally to these destinations: + local PRIVATE_KEY="${DMS_TLS_PATH}/key" + local CERT_CHAIN="${DMS_TLS_PATH}/cert" + + # Fail early: + if [[ -z ${SSL_KEY_PATH} ]] && [[ -z ${SSL_CERT_PATH} ]] then - _notify 'inf' "Configuring certificates using cert ${SSL_CERT_PATH} and key ${SSL_KEY_PATH}" + dms_panic__no_env 'SSL_KEY_PATH or SSL_CERT_PATH' "${SCOPE_SSL_TYPE}" + fi - mkdir -p /etc/postfix/ssl - cp "${SSL_KEY_PATH}" /etc/postfix/ssl/key - cp "${SSL_CERT_PATH}" /etc/postfix/ssl/cert - chmod 600 /etc/postfix/ssl/key - chmod 600 /etc/postfix/ssl/cert + if [[ -n ${SSL_ALT_KEY_PATH} ]] \ + && [[ -n ${SSL_ALT_CERT_PATH} ]] \ + && [[ ! -f ${SSL_ALT_KEY_PATH} ]] \ + && [[ ! -f ${SSL_ALT_CERT_PATH} ]] + then + dms_panic__no_file "(ALT) ${SSL_ALT_KEY_PATH} or ${SSL_ALT_CERT_PATH}" "${SCOPE_SSL_TYPE}" + fi - local PRIVATE_KEY='/etc/postfix/ssl/key' - local CERT_CHAIN='/etc/postfix/ssl/cert' + if [[ -f ${SSL_KEY_PATH} ]] && [[ -f ${SSL_CERT_PATH} ]] + then + cp "${SSL_KEY_PATH}" "${PRIVATE_KEY}" + cp "${SSL_CERT_PATH}" "${CERT_CHAIN}" + chmod 600 "${PRIVATE_KEY}" + chmod 644 "${CERT_CHAIN}" _set_certificate "${PRIVATE_KEY}" "${CERT_CHAIN}" # Support for a fallback certificate, useful for hybrid/dual ECDSA + RSA certs if [[ -n ${SSL_ALT_KEY_PATH} ]] && [[ -n ${SSL_ALT_CERT_PATH} ]] then - _notify 'inf' "Configuring alternative certificates using cert ${SSL_ALT_CERT_PATH} and key ${SSL_ALT_KEY_PATH}" + _notify 'inf' "Configuring fallback certificates using key ${SSL_ALT_KEY_PATH} and cert ${SSL_ALT_CERT_PATH}" _set_alt_certificate "${SSL_ALT_KEY_PATH}" "${SSL_ALT_CERT_PATH}" else # If the Dovecot settings for alt cert has been enabled (doesn't start with `#`), # but required ENV var is missing, reset to disabled state: - sed -i 's|^ssl_alt_key = <.*|#ssl_alt_key = The plaintext authentication is always allowed (and SSL not required) for connections from localhost, as they’re assumed to be secure anyway. + # > This applies to all connections where the local and the remote IP addresses are equal. + # > Also IP ranges specified by login_trusted_networks setting are assumed to be secure. + # + # no => insecure auth allowed, yes (default) => plaintext auth only allowed over a secure connection (insecure connection acceptable for non-plaintext auth) + local DISABLE_PLAINTEXT_AUTH='no' + # no => disabled, yes => optional (secure connections not required), required (default) => mandatory (only secure connections allowed) + local DOVECOT_SSL_ENABLED='no' + sed -i -r "s|^#?(disable_plaintext_auth =).*|\1 ${DISABLE_PLAINTEXT_AUTH}|" /etc/dovecot/conf.d/10-auth.conf + sed -i -r "s|^(ssl =).*|\1 ${DOVECOT_SSL_ENABLED}|" "${DOVECOT_CONFIG_SSL}" ;; - * ) - # Unknown option, default behavior, no action is required - _notify 'warn' "(INSECURE!) ENV var 'SSL_TYPE' is invalid. DO NOT USE FOR PRODUCTION DEPLOYMENT." + + ( 'snakeoil' ) # This is a temporary workaround for testing only, using the insecure snakeoil cert. + # mail_privacy.bats and mail_with_ldap.bats both attempt to make a starttls connection with openssl, + # failing if SSL/TLS is not available. ;; + + ( * ) # Unknown option, panic. + dms_panic__invalid_value 'SSL_TYPE' "${SCOPE_TLS_LEVEL}" + ;; + esac } @@ -1118,8 +1190,8 @@ function _setup_docker_permit if [[ -z ${CONTAINER_IP} ]] then - _notify 'err' "Detecting the container IP address failed. Check if NETWORK_INTERFACE is correctly configured." - _shutdown + _notify 'err' 'Detecting the container IP address failed.' + dms_panic__misconfigured 'NETWORK_INTERFACE' 'Network Setup [docker_permit]' fi while read -r IP @@ -1163,14 +1235,14 @@ function _setup_docker_permit esac } +# Requires ENABLE_POSTFIX_VIRTUAL_TRANSPORT=1 function _setup_postfix_virtual_transport { _notify 'task' 'Setting up Postfix virtual transport' if [[ -z ${POSTFIX_DAGENT} ]] then - _notify 'err' "${POSTFIX_DAGENT} not set." - _shutdown + dms_panic__no_env 'POSTFIX_DAGENT' 'Postfix Setup [virtual_transport]' return 1 fi @@ -1299,7 +1371,6 @@ function _setup_postfix_relay_hosts "smtp_sasl_auth_enable = yes" \ "smtp_sasl_security_options = noanonymous" \ "smtp_sasl_password_maps = texthash:/etc/postfix/sasl_passwd" \ - "smtp_use_tls = yes" \ "smtp_tls_security_level = encrypt" \ "smtp_tls_note_starttls_offer = yes" \ "smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt" \ diff --git a/test/config/dovecot-lmtp/conf.d/10-ssl.conf b/test/config/dovecot-lmtp/conf.d/10-ssl.conf index 001e8646..9cf53830 100644 --- a/test/config/dovecot-lmtp/conf.d/10-ssl.conf +++ b/test/config/dovecot-lmtp/conf.d/10-ssl.conf @@ -6,11 +6,12 @@ ssl = required # PEM encoded X.509 SSL/TLS certificate and private key. They're opened before -# dropping root privileges, so keep the key file unreadable by anyone but -# root. Included doc/mkcert.sh can be used to easily generate self-signed -# certificate, just make sure to update the domains in dovecot-openssl.cnf -ssl_cert = must be well formatted" { - run docker exec mail /bin/sh -c "addmailuser quota_user@domain.tld mypassword" - assert_success + run docker exec mail /bin/sh -c "addmailuser quota_user@domain.tld mypassword" + assert_success - run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 26GIGOTS" - assert_failure - run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 123" - assert_failure - run docker exec mail /bin/sh -c "setquota quota_user@domain.tld M" - assert_failure - run docker exec mail /bin/sh -c "setquota quota_user@domain.tld -60M" - assert_failure + run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 26GIGOTS" + assert_failure + run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 123" + assert_failure + run docker exec mail /bin/sh -c "setquota quota_user@domain.tld M" + assert_failure + run docker exec mail /bin/sh -c "setquota quota_user@domain.tld -60M" + assert_failure - run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10B" - assert_success - run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10k" - assert_success - run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10M" - assert_success - run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10G" - assert_success - run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10T" - assert_success + run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10B" + assert_success + run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10k" + assert_success + run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10M" + assert_success + run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10G" + assert_success + run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10T" + assert_success - run docker exec mail /bin/sh -c "delmailuser -y quota_user@domain.tld" - assert_success + run docker exec mail /bin/sh -c "delmailuser -y quota_user@domain.tld" + assert_success } @test "checking quota: delquota user must be existing" { - run docker exec mail /bin/sh -c "addmailuser quota_user@domain.tld mypassword" - assert_success + run docker exec mail /bin/sh -c "addmailuser quota_user@domain.tld mypassword" + assert_success - run docker exec mail /bin/sh -c "delquota uota_user@domain.tld" - assert_failure - run docker exec mail /bin/sh -c "delquota quota_user" - assert_failure - run docker exec mail /bin/sh -c "delquota dontknowyou@domain.tld" - assert_failure + run docker exec mail /bin/sh -c "delquota uota_user@domain.tld" + assert_failure + run docker exec mail /bin/sh -c "delquota quota_user" + assert_failure + run docker exec mail /bin/sh -c "delquota dontknowyou@domain.tld" + assert_failure - run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10T" - assert_success - run docker exec mail /bin/sh -c "delquota quota_user@domain.tld" - assert_success - run docker exec mail /bin/sh -c "grep -i 'quota_user@domain.tld' /tmp/docker-mailserver/dovecot-quotas.cf" - assert_failure + run docker exec mail /bin/sh -c "setquota quota_user@domain.tld 10T" + assert_success + run docker exec mail /bin/sh -c "delquota quota_user@domain.tld" + assert_success + run docker exec mail /bin/sh -c "grep -i 'quota_user@domain.tld' /tmp/docker-mailserver/dovecot-quotas.cf" + assert_failure - run docker exec mail /bin/sh -c "delmailuser -y quota_user@domain.tld" - assert_success + run docker exec mail /bin/sh -c "delmailuser -y quota_user@domain.tld" + assert_success } @test "checking quota: delquota allow when no quota for existing user" { - run docker exec mail /bin/sh -c "addmailuser quota_user@domain.tld mypassword" - assert_success + run docker exec mail /bin/sh -c "addmailuser quota_user@domain.tld mypassword" + assert_success - run docker exec mail /bin/sh -c "grep -i 'quota_user@domain.tld' /tmp/docker-mailserver/dovecot-quotas.cf" - assert_failure + run docker exec mail /bin/sh -c "grep -i 'quota_user@domain.tld' /tmp/docker-mailserver/dovecot-quotas.cf" + assert_failure - run docker exec mail /bin/sh -c "delquota quota_user@domain.tld" - assert_success - run docker exec mail /bin/sh -c "delquota quota_user@domain.tld" - assert_success + run docker exec mail /bin/sh -c "delquota quota_user@domain.tld" + assert_success + run docker exec mail /bin/sh -c "delquota quota_user@domain.tld" + assert_success - run docker exec mail /bin/sh -c "delmailuser -y quota_user@domain.tld" - assert_success + run docker exec mail /bin/sh -c "delmailuser -y quota_user@domain.tld" + assert_success } @test "checking quota: dovecot quota present in postconf" { @@ -1216,60 +1205,6 @@ EOF assert_failure } - -# -# PCI compliance -# - -# dovecot -@test "checking dovecot: only A grade TLS ciphers are used" { - run docker run --rm -i --link mail:dovecot \ - --entrypoint sh instrumentisto/nmap -c \ - 'nmap --script ssl-enum-ciphers -p 993 dovecot | grep "least strength: A"' - assert_success -} - -@test "checking dovecot: nmap produces no warnings on TLS ciphers verifying" { - run docker run --rm -i --link mail:dovecot \ - --entrypoint sh instrumentisto/nmap -c \ - 'nmap --script ssl-enum-ciphers -p 993 dovecot | grep "warnings" | wc -l' - assert_success - assert_output 0 -} - -# postfix submission TLS -@test "checking postfix submission: only A grade TLS ciphers are used" { - run docker run --rm -i --link mail:postfix \ - --entrypoint sh instrumentisto/nmap -c \ - 'nmap --script ssl-enum-ciphers -p 587 postfix | grep "least strength: A"' - assert_success -} - -@test "checking postfix submission: nmap produces no warnings on TLS ciphers verifying" { - run docker run --rm -i --link mail:postfix \ - --entrypoint sh instrumentisto/nmap -c \ - 'nmap --script ssl-enum-ciphers -p 587 postfix | grep "warnings" | wc -l' - assert_success - assert_output 0 -} - -# postfix smtps SSL -@test "checking postfix smtps: only A grade TLS ciphers are used" { - run docker run --rm -i --link mail:postfix \ - --entrypoint sh instrumentisto/nmap -c \ - 'nmap --script ssl-enum-ciphers -p 465 postfix | grep "least strength: A"' - assert_success -} - -@test "checking postfix smtps: nmap produces no warnings on TLS ciphers verifying" { - run docker run --rm -i --link mail:postfix \ - --entrypoint sh instrumentisto/nmap -c \ - 'nmap --script ssl-enum-ciphers -p 465 postfix | grep "warnings" | wc -l' - assert_success - assert_output 0 -} - - # # supervisor #