Skip to content

Commit

Permalink
Add DKIM support
Browse files Browse the repository at this point in the history
  • Loading branch information
macropin committed Jun 8, 2017
1 parent 2e4e2fb commit b289f75
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dkim.key
10 changes: 7 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ RUN echo mail > /etc/hostname; \

# Install packages
RUN apt-get update && \
apt-get install -y --no-install-recommends postfix mailutils busybox-syslogd curl ca-certificates && \
apt-get install -y --no-install-recommends postfix mailutils busybox-syslogd opendkim curl ca-certificates && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

Expand All @@ -26,14 +26,18 @@ RUN DIR=$(mktemp -d) && cd ${DIR} && \
tar -xzf s6.tar.gz -C / && \
rm -rf ${DIR}

# Configure Postfix
# Configure Postfix / dkim
RUN postconf -e smtpd_banner="\$myhostname ESMTP" && \
# Enable submission
postconf -Me submission/inet="submission inet n - - - - smtpd" && \
# Cache spool dir as template
cp -a /var/spool/postfix /var/spool/postfix.cache && \
# Remove snakeoil certs
rm -f /etc/ssl/private/ssl-cert-snakeoil.key /etc/ssl/certs/ssl-cert-snakeoil.pem
rm -f /etc/ssl/private/ssl-cert-snakeoil.key /etc/ssl/certs/ssl-cert-snakeoil.pem && \
rm -f /etc/opendkim.conf && \
mkdir /etc/opendkim/

COPY opendkim.conf.sh /etc/

COPY s6 /etc/s6/

Expand Down
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,10 @@ run:
@echo "Running ${ID} @ smtp://${IP}"
@docker attach ${ID}
@docker kill ${ID}

run-dkim:
$(eval ID := $(shell docker run -d --hostname mail.example.com -e MAILNAME=mail.example.com -e DKIM_DOMAINS=foo.example.com,bar.example.com -e USE_DKIM=yes -v `pwd`/dkim.key:/etc/opendkim/dkim.key ${docker_tag}))
$(eval IP := $(shell docker inspect --format '{{ .NetworkSettings.IPAddress }}' ${ID}))
@echo "Running ${ID} @ smtp://${IP}"
@docker attach ${ID}
@docker kill ${ID}
22 changes: 15 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Postfix SMTP Relay.

Fairly simple drop-in container for SMTP relaying. Use wherever a connected service
requires SMTP sending capabilities.
requires SMTP sending capabilities. Supports TLS out of the box and DKIM (if enabled and configured).

## Environment Variables

Expand All @@ -14,16 +14,24 @@ requires SMTP sending capabilities.

TLS parameters:

- `USETLS` - Enable opportunistic TLS. default `yes`
- `TLSKEY` - Default `/etc/ssl/private/ssl-cert-snakeoil.key`
- `TLSCRT` - Default `/etc/ssl/certs/ssl-cert-snakeoil.pem`
- `TLSCA` - Default ''
- `USE_TLS` - Enable opportunistic TLS. Default `yes`
- `TLS_KEY` - Default `/etc/ssl/private/ssl-cert-snakeoil.key`
- `TLS_CRT` - Default `/etc/ssl/certs/ssl-cert-snakeoil.pem`
- `TLS_CA` - Default ''

NB. The snake-oil certificate will generated on start if required.
NB. A "snake-oil" certificate will generated on start if required.

DKIM parameters:

- `USE_DKIM` - Enable DKIM. Default `no`
- `DKIM_KEYFILE` - DKIM Keyfile location. Default `/etc/opendkim/dkim.key`
- `DKIM_DOMAINS` - Domains to sign. Default to MAILNAME. Multiple domains will use the same key and selector.
- `DKIM_SELECTOR` - DKIM key selector. Default `mail`. `<selector>._domainkey.<domain>` is used for resolving the public key in DNS.

## Volumes

No volumes are defined. If you want persistent spool storage then mount `/var/spool/postfix` outside of the container.
No volumes are defined. If you want persistent spool storage then mount
`/var/spool/postfix` outside of the container.

## Test email

Expand Down
77 changes: 77 additions & 0 deletions opendkim.conf.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env bash

set -e

OUTPUT='/etc/opendkim.conf'

# exit if config already exists
[ -f "${OUTPUT}" ] && exit 0

# defaults
: ${DKIM_KEYFILE:='/etc/opendkim/dkim.key'}
: ${DKIM_DOMAINS:="${MAILNAME}"}
: ${DKIM_SELECTOR:='mail'}

# Checks
if [ ! -f "${DKIM_KEYFILE}" ]; then
echo "dkim >> Error: DKIM_KEYFILE ${DKIM_KEYFILE} not found"
# shutdown everything
s6-svscanctl -t /etc/s6
exit 128
else
echo "dkim >> Setting mode and owner on $DKIM_KEYFILE"
chown opendkim:opendkim ${DKIM_KEYFILE}
chmod 400 ${DKIM_KEYFILE}
fi

# Status Output
echo "dkim >> Setting DKIM_KEYFILE to $DKIM_KEYFILE"
echo "dkim >> Setting DKIM_DOMAINS to $DKIM_DOMAINS"
echo "dkim >> Setting DKIM_SELECTOR to $DKIM_SELECTOR"

# Render the dkim config
cat > ${OUTPUT} <<EOF
# This is a basic configuration that can easily be adapted to suit a standard
# installation. For more advanced options, see opendkim.conf(5) and/or
# /usr/share/doc/opendkim/examples/opendkim.conf.sample.
# Log to syslog
Syslog yes
SyslogSuccess yes
# Required to use local socket with MTAs that access the socket as a non-
# privileged user (e.g. Postfix)
UMask 002
## Create a socket through which your MTA can communicate.
Socket inet:8891@localhost
# Sign for example.com with key in /etc/mail/dkim.key using
# selector '2007' (e.g. 2007._domainkey.example.com)
Domain ${DKIM_DOMAINS}
KeyFile ${DKIM_KEYFILE}
Selector ${DKIM_SELECTOR}
# Commonly-used options; the commented-out versions show the defaults.
Canonicalization relaxed
Mode s
#SubDomains no
#ADSPAction continue
## Specifies whether or not the filter should generate report mail back
## to senders when verification fails and an address for such a purpose
## is provided. See opendkim.conf(5) for details.
SendReports yes
# Always oversign From (sign using actual From and a null From to prevent
# malicious signatures header fields (From and/or others) between the signer
# and the verifier. From is oversigned by default in the Debian pacakge
# because it is often the identity key used by reputation systems and thus
# somewhat security sensitive.
OversignHeaders From
# List domains to use for RFC 6541 DKIM Authorized Third-Party Signatures
# (ATPS) (experimental)
#ATPSDomains example.com
EOF
3 changes: 3 additions & 0 deletions s6/opendkim/finish
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

echo "FINISH $(pwd) WITH: ${@}"
36 changes: 36 additions & 0 deletions s6/opendkim/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash

set -e

[ "$DEBUG" == 'true' ] && set -x

# Fix issue with dpkg-reconfigure and locales not installed "perl: warning: Setting locale failed."
unset LANG

cd /etc/s6/opendkim

# Defaults
: ${USE_DKIM:='no'}

# Exit if dkim disabled
if [ "${USE_DKIM}" != "yes" ]; then
echo "dkim >> USE_DKIM = ${USE_DKIM}. Not starting opendkim."
s6-svc -d $(pwd)
exit
fi

# Render config template
/etc/opendkim.conf.sh

# exit cleanly
trap "{ /usr/sbin/service opendkim stop; }" EXIT

# start postfix
/usr/sbin/service opendkim start

sleep 10 # wait for startup

# watch for opendkim exit
while kill -0 $(pidof opendkim) 2>/dev/null; do
sleep 1
done
46 changes: 28 additions & 18 deletions s6/postfix/run
Original file line number Diff line number Diff line change
Expand Up @@ -14,49 +14,59 @@ fi

# Defaults
if [ -z "$MAILNAME" ]; then
echo "Error: MAILNAME not specified"
echo "postfix >> Error: MAILNAME not specified"
exit 128
fi

if [ -z "$MYNETWORKS" ]; then
MYNETWORKS='127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16'
echo "Warning: MYNETWORKS not specified, allowing all private IPs"
echo "postfix >> Warning: MYNETWORKS not specified, allowing all private IPs"
fi

if [ -z "$SIZELIMIT" ]; then
SIZELIMIT=15728640 # 10Meg with headroom
fi

# DKIM
if [ "${USE_DKIM}" == "yes" ]; then
# TODO s6-svwait for dkim
echo "postfix >> Enabling dkim milter"
postconf -e milter_protocol="6"
postconf -e milter_default_action="accept"
postconf -e smtpd_milters="inet:localhost:8891"
postconf -e non_smtpd_milters="inet:localhost:8891"
fi

# TLS
: ${USETLS:='yes'}
: ${TLSKEY:='/etc/ssl/private/ssl-cert-snakeoil.key'}
: ${TLSCRT:='/etc/ssl/certs/ssl-cert-snakeoil.pem'}
: ${TLSCA:=''}
: ${USE_TLS:='yes'}
: ${TLS_KEY:='/etc/ssl/private/ssl-cert-snakeoil.key'}
: ${TLS_CRT:='/etc/ssl/certs/ssl-cert-snakeoil.pem'}
: ${TLS_CA:=''}

echo "Setting smtpd_use_tls to $USETLS"
postconf -e smtpd_use_tls="$USETLS"
echo "postfix >> Setting smtpd_use_tls to $USE_TLS"
postconf -e smtpd_use_tls="$USE_TLS"

if [ "${USETLS}" == "yes" ]; then
if [ "${TLSKEY}" == "/etc/ssl/private/ssl-cert-snakeoil.key" ]; then
echo "Generating snakeoil SSL cert"
if [ "${USE_TLS}" == "yes" ]; then
if [ "${TLS_KEY}" == "/etc/ssl/private/ssl-cert-snakeoil.key" ]; then
echo "postfix >> Generating snakeoil SSL cert"
dpkg-reconfigure -f noninteractive ssl-cert
fi
echo "Setting smtpd_tls parameters"
postconf -e smtpd_tls_key_file="$TLSKEY"
postconf -e smtpd_tls_cert_file="$TLSCRT"
postconf -e smtpd_tls_CAfile="$TLSCA"
echo "postfix >> Setting smtpd_tls parameters"
postconf -e smtpd_tls_key_file="$TLS_KEY"
postconf -e smtpd_tls_cert_file="$TLS_CRT"
postconf -e smtpd_tls_CAfile="$TLS_CA"
fi

# Configure Postfix General parameters
echo "Setting mailname to $MAILNAME"
echo "postfix >> Setting mailname to $MAILNAME"
echo $MAILNAME > /etc/mailname
postconf -e myhostname="$MAILNAME"
postconf -e mydestination="$MAILNAME"

echo "Setting mynetworks to $MYNETWORKS"
echo "postfix >> Setting mynetworks to $MYNETWORKS"
postconf -e mynetworks="$MYNETWORKS"

echo "Setting message_size_limit to $SIZELIMIT"
echo "postfix >> Setting message_size_limit to $SIZELIMIT"
postconf -e message_size_limit="$SIZELIMIT"

# exit cleanly
Expand Down
2 changes: 1 addition & 1 deletion s6/syslogd/run
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
# Defaults
: ${LOGOUTPUT:='/dev/stdout'}

echo "Setting syslogd output to ${LOGOUTPUT}"
echo "syslogd >> Setting syslogd output to ${LOGOUTPUT}"

exec syslogd -n -O ${LOGOUTPUT} -S

0 comments on commit b289f75

Please sign in to comment.