diff --git a/postfix/Dockerfile b/postfix/Dockerfile index 2408ef3e..4dc1c893 100644 --- a/postfix/Dockerfile +++ b/postfix/Dockerfile @@ -1,10 +1,8 @@ FROM alpine -RUN apk add --no-cache bash postfix postfix-sqlite postfix-pcre rsyslog +RUN apk add --no-cache postfix postfix-sqlite postfix-pcre rsyslog python py-jinja2 -COPY conf /etc/postfix -COPY rsyslog.conf /etc/rsyslog.conf +COPY conf /conf +COPY start.py /start.py -COPY start.sh /start.sh - -CMD ["/start.sh"] +CMD /start.py diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf index 5e37543f..e1ba19fc 100644 --- a/postfix/conf/main.cf +++ b/postfix/conf/main.cf @@ -38,24 +38,7 @@ recipient_delimiter = {{ RECIPIENT_DELIMITER }} # General TLS configuration tls_high_cipherlist = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA tls_preempt_cipherlist = yes - -# Only one key/certificate pair is used, SNI not being supported by all -# services and not a strong requirement. Also, TLS is enforced for submission -# and smtps in master.cf. -smtpd_tls_security_level = may -smtpd_tls_cert_file=/certs/cert.pem -smtpd_tls_key_file=/certs/key.pem -smtpd_tls_dh1024_param_file=/certs/dhparam.pem -smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache - -# Server-side TLS is hardened, it should be up to the client to update his or -# her TLS stack in order to connect to the mail server. Hardening is based on -# https://bettercrypto.org/static/applied-crypto-hardening.pdf -smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3 -smtpd_tls_protocols = !SSLv2, !SSLv3 -smtpd_tls_ciphers = high -smtpd_tls_mandatory_ciphers = high - +tls_ssl_options = NO_COMPRESSION # Outgoing TLS is more flexible because 1. not all receiving servers will # support TLS, 2. not all will have and up-to-date TLS stack. @@ -64,23 +47,6 @@ smtp_tls_mandatory_protocols = !SSLv2, !SSLv3 smtp_tls_protocols =!SSLv2,!SSLv3 smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache -# General TLS hardening -tls_ssl_options = NO_COMPRESSION -tls_preempt_cipherlist = yes - -############### -# SASL -############### - -smtpd_sasl_local_domain = $myhostname - -# Authentication is done against dovecot, which acts as the main authention -# source -smtpd_sasl_type = dovecot -smtpd_sasl_path = inet:imap:2102 -smtpd_sasl_auth_enable = yes -smtpd_sasl_security_options = noanonymous - ############### # Virtual ############### @@ -118,15 +84,14 @@ smtpd_sender_restrictions = reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unlisted_sender, - reject_sender_login_mismatch, permit # Recipient restrictions: smtpd_recipient_restrictions = + permit_mynetworks, reject_unauth_pipelining, reject_non_fqdn_recipient, reject_unknown_recipient_domain, - permit_mynetworks, permit ############### diff --git a/postfix/conf/master.cf b/postfix/conf/master.cf index a196f496..47cb4af6 100644 --- a/postfix/conf/master.cf +++ b/postfix/conf/master.cf @@ -3,17 +3,6 @@ # Exposed SMTP services smtp inet n - n - - smtpd - -o smtpd_helo_restrictions=permit_mynetworks,permit -submission inet n - n - - smtpd - -o smtpd_tls_security_level=encrypt - -o smtpd_sasl_auth_enable=yes - -o smtpd_client_restrictions=permit_sasl_authenticated,reject - -o cleanup_service_name=outclean -smtps inet n - n - - smtpd - -o smtpd_tls_security_level=encrypt - -o smtpd_sasl_auth_enable=yes - -o smtpd_tls_wrappermode=yes - -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o cleanup_service_name=outclean # Additional services diff --git a/postfix/rsyslog.conf b/postfix/conf/rsyslog.conf similarity index 100% rename from postfix/rsyslog.conf rename to postfix/conf/rsyslog.conf diff --git a/postfix/start.py b/postfix/start.py new file mode 100755 index 00000000..994c4431 --- /dev/null +++ b/postfix/start.py @@ -0,0 +1,38 @@ +#!/usr/bin/python + +import jinja2 +import os +import socket +import glob +import shutil + +convert = lambda src, dst: open(dst, "w").write(jinja2.Template(open(src).read()).render(**os.environ)) + +# Actual startup script +os.environ["FRONT_ADDRESS"] = socket.gethostbyname("front") + +for postfix_file in glob.glob("/conf/*.cf"): + convert(postfix_file, os.path.join("/etc/postfix", os.path.basename(postfix_file))) + +if os.path.exists("/overrides/postfix.cf"): + for line in open("/overrides/postfix.cf").read().strip().split("\n"): + os.system('postconf -e "{}"'.format(line)) + +if os.path.exists("/overrides/postfix.master"): + for line in open("/overrides/postfix.master").read().strip().split("\n"): + os.system('postconf -Me "{}"'.format(line)) + +for map_file in glob.glob("/overrides/*.map"): + destination = os.path.join("/etc/postfix", os.path.basename(map_file)) + shutil.copyfile(map_file, destination) + os.system("postmap {}".format(destination)) + os.remove(destination) + +convert("/conf/rsyslog.conf", "/etc/rsyslog.conf") + +# Run postfix +if os.path.exists("/var/run/rsyslogd.pid"): + os.remove("/var/run/rsyslogd.pid") +os.system("/usr/lib/postfix/post-install meta_directory=/etc/postfix create-missing") +os.system("/usr/lib/postfix/master &") +os.execv("/usr/sbin/rsyslogd", ["rsyslogd", "-n"]) diff --git a/postfix/start.sh b/postfix/start.sh deleted file mode 100755 index e34543a5..00000000 --- a/postfix/start.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -# Substitute configuration -for VARIABLE in `env | cut -f1 -d=`; do - sed -i "s={{ $VARIABLE }}=${!VARIABLE}=g" /etc/postfix/*.cf -done - -# Override Postfix main configuration -if [ -f /overrides/postfix.cf ]; then - while read line; do - postconf -e "$line" - done < /overrides/postfix.cf - echo "Loaded '/overrides/postfix.cf'" -else - echo "No extra postfix settings loaded because optional '/overrides/postfix.cf' not provided." -fi - -# Override Postfix master configuration -if [ -f /overrides/postfix.master ]; then - while read line; do - postconf -Me "$line" - done < /overrides/postfix.master - echo "Loaded '/overrides/postfix.master'" -else - echo "No extra postfix settings loaded because optional '/overrides/postfix.master' not provided." -fi - -# Include table-map files -if ls -A /overrides/*.map 1> /dev/null 2>&1; then - cp /overrides/*.map /etc/postfix/ - postmap /etc/postfix/*.map - rm /etc/postfix/*.map - chown root:root /etc/postfix/*.db - chmod 0600 /etc/postfix/*.db - echo "Loaded 'map files'" -else - echo "No extra map files loaded because optional '/overrides/*.map' not provided." -fi - -# Actually run Postfix -rm -f /var/run/rsyslogd.pid -chown -R postfix: /queue -/usr/lib/postfix/post-install meta_directory=/etc/postfix create-missing -/usr/lib/postfix/master & -exec rsyslogd -n