Merge from Master

This commit is contained in:
alinmear 2017-01-09 20:39:05 +01:00
commit 291244e72f
15 changed files with 595 additions and 266 deletions

View File

@ -5,8 +5,18 @@ language: bash
sudo: required
services:
- docker
install:
- travis_wait make build-no-cache
script:
- make all
- make generate-accounts run fixtures tests
after_script:
- make clean
notifications:
slack:
secure: TTo1z9nbZCWcIdfPwypubNa3y+pwvfgDGlzEVAGEuK7uuIpmEoAcAUNSSPTnbewDGHnDl8t/ml93MtvP+a+IVuAKytMqF39PHyoZO7aUl9J62V+G75OmnyGjXGJm40pQosCS6LzqoRRYXotl9+fwH568Kf4ifXCrMZX1d+ir7Ww=
webhooks:
urls:
- https://webhooks.gitter.im/e/7c5e56a8257cdec003ab
on_success: always
on_failure: always
on_start: never

32
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,32 @@
# Contributing
`docker-mailserver` is OpenSource. That means that you can contribute on enhancements, bug fixing or improving the documentation in the Wiki.
## Open an issue
When opening an issue, please provide details use case to let the community reproduce your problem.
Please start the mail server with env `DMS_DEBUG=1` and paste the ouput into the issue.
## Pull Requests
#### Project architecture
├── config # User: personal configurations
├── target # Developer: default server configuration, used when building the image
└── test # Developer: integration tests to check that everything keeps working
#### Development Workflow
The development workflow is the following:
- Fork project and clone your fork
- Create a branch using `git checkout -b branch_name` (you can use `issue-xxx` if fixing an existing issue)
- Code :-)
- Add integration tests in `test/tests.bats`
- Use `make` to build image locally and run tests
- Document your improvements
- [Commit](https://help.github.com/articles/closing-issues-via-commit-messages/), push and make a pull-request
- Pull-request is automatically tested on Travis
- When tests are green, your branch is merged into `master`
- `master` is automatically tested on Travis
- Docker builds a new `latest` image

View File

@ -102,6 +102,7 @@ RUN sed -i 's/START_DAEMON=no/START_DAEMON=yes/g' /etc/default/fetchmail
# Configures Postfix
COPY target/postfix/main.cf target/postfix/master.cf /etc/postfix/
RUN echo "" > /etc/aliases
# Configuring Logs
RUN sed -i -r "/^#?compress/c\compress\ncopytruncate" /etc/logrotate.conf && \
@ -117,8 +118,7 @@ RUN sed -i -r "/^#?compress/c\compress\ncopytruncate" /etc/logrotate.conf && \
sed -i -r 's|/var/log/mail|/var/log/mail/mail|g' /etc/logrotate.d/rsyslog
# Get LetsEncrypt signed certificate
RUN curl -s https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem > /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem && \
curl -s https://letsencrypt.org/certs/lets-encrypt-x2-cross-signed.pem > /etc/ssl/certs/lets-encrypt-x2-cross-signed.pem
RUN curl -s https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem > /etc/ssl/certs/lets-encrypt-x3-cross-signed.pem
COPY ./target/bin /usr/local/bin
# Start-mailserver script

View File

@ -22,56 +22,55 @@ run:
-v "`pwd`/test/config":/tmp/docker-mailserver \
-v "`pwd`/test":/tmp/docker-mailserver-test \
-v "`pwd`/test/onedir":/var/mail-state \
-e ENABLE_CLAMAV=1 \
-e ENABLE_SPAMASSASSIN=1 \
-e SA_TAG=1.0 \
-e SA_TAG2=2.0 \
-e SA_KILL=3.0 \
-e VIRUSMAILS_DELETE_DELAY=7 \
-e SASL_PASSWD="external-domain.com username:password" \
-e ENABLE_MANAGESIEVE=1 \
-e PERMIT_DOCKER=host\
-e PERMIT_DOCKER=host \
-e DMS_DEBUG=0 \
-h mail.my-domain.com -t $(NAME)
sleep 20
sleep 15
docker run -d --name mail_pop3 \
-v "`pwd`/test/config":/tmp/docker-mailserver \
-v "`pwd`/test":/tmp/docker-mailserver-test \
-v "`pwd`/test/config/letsencrypt":/etc/letsencrypt/live \
-e ENABLE_POP3=1 \
-e DMS_DEBUG=1 \
-e SSL_TYPE=letsencrypt \
-h mail.my-domain.com -t $(NAME)
sleep 20
sleep 15
docker run -d --name mail_smtponly \
-v "`pwd`/test/config":/tmp/docker-mailserver \
-v "`pwd`/test":/tmp/docker-mailserver-test \
-e SMTP_ONLY=1 \
-e PERMIT_DOCKER=network\
-h mail.my-domain.com -t $(NAME)
sleep 20
sleep 15
docker run -d --name mail_fail2ban \
-v "`pwd`/test/config":/tmp/docker-mailserver \
-v "`pwd`/test":/tmp/docker-mailserver-test \
-e ENABLE_FAIL2BAN=1 \
--cap-add=NET_ADMIN \
-h mail.my-domain.com -t $(NAME)
sleep 20
sleep 15
docker run -d --name mail_fetchmail \
-v "`pwd`/test/config":/tmp/docker-mailserver \
-v "`pwd`/test":/tmp/docker-mailserver-test \
-e ENABLE_FETCHMAIL=1 \
--cap-add=NET_ADMIN \
-h mail.my-domain.com -t $(NAME)
sleep 20
docker run -d --name mail_disabled_amavis \
sleep 15
docker run -d --name mail_disabled_clamav_spamassassin \
-v "`pwd`/test/config":/tmp/docker-mailserver \
-v "`pwd`/test":/tmp/docker-mailserver-test \
-e DISABLE_AMAVIS=1 \
-e ENABLE_CLAMAV=0 \
-e ENABLE_SPAMASSASSIN=0 \
-h mail.my-domain.com -t $(NAME)
sleep 20
docker run -d --name mail_disabled_clamav \
-v "`pwd`/test/config":/tmp/docker-mailserver \
-v "`pwd`/test":/tmp/docker-mailserver-test \
-e DISABLE_CLAMAV=1 \
-h mail.my-domain.com -t $(NAME)
sleep 20
sleep 15
docker run -d --name mail_manual_ssl \
-v "`pwd`/test/config":/tmp/docker-mailserver \
-v "`pwd`/test":/tmp/docker-mailserver-test \
@ -79,11 +78,11 @@ run:
-e SSL_CERT_PATH=/tmp/docker-mailserver/letsencrypt/mail.my-domain.com/fullchain.pem \
-e SSL_KEY_PATH=/tmp/docker-mailserver/letsencrypt/mail.my-domain.com/privkey.pem \
-h mail.my-domain.com -t $(NAME)
sleep 20
sleep 15
docker run -d --name ldap_for_mail \
-e LDAP_DOMAIN="localhost.localdomain" \
-h mail.my-domain.com -t ldap
sleep 20
sleep 15
docker run -d --name mail_with_ldap \
-v "`pwd`/test/config":/tmp/docker-mailserver \
-v "`pwd`/test":/tmp/docker-mailserver-test \
@ -100,8 +99,17 @@ run:
-e POSTMASTER_ADDRESS=postmaster@localhost.localdomain \
--link ldap_for_mail:ldap \
-h mail.my-domain.com -t $(NAME)
sleep 15
docker run -d --name mail_with_imap \
-v "`pwd`/test/config":/tmp/docker-mailserver \
-v "`pwd`/test":/tmp/docker-mailserver-test \
-e ENABLE_SASLAUTHD=1 \
-e SASLAUTHD_MECHANISMS=rimap \
-e SASLAUTHD_MECH_OPTIONS=127.0.0.1 \
-e POSTMASTER_ADDRESS=postmaster@localhost.localdomain \
-h mail.my-domain.com -t $(NAME)
# Wait for containers to fully start
sleep 20
sleep 15
docker run -d --name mail_lmtp_ip \
-v "`pwd`/test/config":/tmp/docker-mailserver \
-v "`pwd`/test/config/dovecot-lmtp":/etc/dovecot \
@ -109,7 +117,7 @@ run:
-e ENABLE_POSTFIX_VIRTUAL_TRANSPORT=1 \
-e POSTFIX_DAGENT=lmtp:127.0.0.1:24 \
-h mail.my-domain.com -t $(NAME)
sleep 20
sleep 15
fixtures:
cp config/postfix-accounts.cf config/postfix-accounts.cf.bak
@ -129,6 +137,7 @@ fixtures:
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-catchall-local.txt"
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/sieve-spam-folder.txt"
docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/non-existing-user.txt"
docker exec mail_disabled_clamav_spamassassin /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user.txt"
# postfix virtual transport lmtp
docker exec mail_lmtp_ip /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user.txt"
# Wait for mails to be analyzed
@ -147,11 +156,11 @@ clean:
mail_fail2ban \
mail_fetchmail \
fail-auth-mailer \
mail_disabled_amavis \
mail_disabled_clamav \
mail_disabled_clamav_spamassassin \
mail_manual_ssl \
ldap_for_mail \
mail_with_ldap \
mail_with_imap \
mail_lmtp_ip
@if [ -f config/postfix-accounts.cf.bak ]; then\

View File

@ -20,6 +20,7 @@ Includes:
- fetchmail
- basic [sieve support](https://github.com/tomav/docker-mailserver/wiki/Configure-Sieve-filters) using dovecot
- [LetsEncrypt](https://letsencrypt.org/) and self-signed certificates
- persistent data and state (but think about backups!)
- [integration tests](https://travis-ci.org/tomav/docker-mailserver)
- [automated builds on docker hub](https://hub.docker.com/r/tvial/docker-mailserver/)
@ -37,13 +38,14 @@ Before you open an issue, please have a look this `README`, the [Wiki](https://g
Adapt this file with your FQDN. Install [docker-compose](https://docs.docker.com/compose/) in the version `1.6` or higher.
Your configs must be mounted in `/tmp/docker-mailserver/`. To understand how things work on boot, please have a look to [start-mailserver.sh](https://github.com/tomav/docker-mailserver/blob/master/target/start-mailserver.sh)
```yaml
version: '2'
services:
mail:
image: tvial/docker-mailserver:latest
# build: .
image: tvial/docker-mailserver:2.1
hostname: mail
domainname: domain.com
container_name: mail
@ -54,11 +56,22 @@ services:
- "993:993"
volumes:
- maildata:/var/mail
- mailstate:/var/mail-state
- ./config/:/tmp/docker-mailserver/
environment:
- ENABLE_SPAMASSASSIN=1
- ENABLE_CLAMAV=1
- ENABLE_FAIL2BAN=1
- ONE_DIR=1
- DMS_DEBUG=0
cap_add:
- NET_ADMIN
volumes:
maildata:
driver: local
mailstate:
driver: local
```
#### Create your mail accounts
@ -81,6 +94,8 @@ Don't forget to adapt MAIL_USER and MAIL_PASS to your needs
Now the keys are generated, you can configure your DNS server by just pasting the content of `config/opendkim/keys/domain.tld/mail.txt` in your `domain.tld.hosts` zone.
Note: you can also manage email accounts, DKIM keys and more with the [setup.sh convenience script](https://github.com/tomav/docker-mailserver/wiki/Setup-docker-mailserver-using-the-script-setup.sh).
#### Start the container
docker-compose up -d mail
@ -93,6 +108,39 @@ Please check [how the container starts](https://github.com/tomav/docker-mailserv
Value in **bold** is the default value.
##### DMS_DEBUG
- **0** => Debug disabled
- 1 => Enables debug on startup
#### ENABLE_CLAMAV
- **0** => Clamav is disabled
- 1 => Clamav is enabled
#### ENABLE_SPAMASSASSIN
- **0** => Spamassassin is disabled
- 1 => Spamassassin is enabled
##### SA_TAG
- **2.0** => add spam info headers if at, or above that level
Note: this spamassassin setting needs `ENABLE_SPAMASSASSIN=1`
##### SA_TAG2
- **6.31** => add 'spam detected' headers at that level
Note: this spamassassin setting needs `ENABLE_SPAMASSASSIN=1`
##### SA_KILL
- **6.31** => triggers spam evasive actions
Note: this spamassassin setting needs `ENABLE_SPAMASSASSIN=1`
##### ENABLE_POP3
- **empty** => POP3 service disabled
@ -100,7 +148,7 @@ Value in **bold** is the default value.
##### ENABLE_FAIL2BAN
- **empty** => fail2ban service disabled
- **0** => fail2ban service disabled
- 1 => Enables fail2ban service
If you enable Fail2Ban, don't forget to add the following lines to your `docker-compose.yml`:
@ -116,7 +164,7 @@ Otherwise, `iptables` won't be able to ban IPs.
- 1 => Enables Managesieve on port 4190
##### ENABLE_FETCHMAIL
- **empty** => `fetchmail` disabled
- **0** => `fetchmail` disabled
- 1 => `fetchmail` enabled
##### ENABLE_LDAP
@ -153,21 +201,9 @@ Otherwise, `iptables` won't be able to ban IPs.
- **empty** => postmaster@domain.com
- => Specify the postmaster address
##### SA_TAG
- **2.0** => add spam info headers if at, or above that level
##### SA_TAG2
- **6.31** => add 'spam detected' headers at that level
##### SA_KILL
- **6.31** => triggers spam evasive actions
##### ENABLE_SASLAUTHD
- **empty** => `saslauthd` is disabled
- **0** => `saslauthd` is disabled
- 1 => `saslauthd` is enabled
##### SASLAUTHD_MECHANISMS

View File

@ -2,7 +2,7 @@ version: '2'
services:
mail:
image: tvial/docker-mailserver:v2
image: tvial/docker-mailserver:2.1
hostname: mail
domainname: domain.com
container_name: mail
@ -13,12 +13,19 @@ services:
- "993:993"
volumes:
- maildata:/var/mail
- mailstate:/var/mail-state
- ./config/:/tmp/docker-mailserver/
environment:
- ENABLE_SPAMASSASSIN=1
- ENABLE_CLAMAV=1
- ENABLE_FAIL2BAN=1
- ONE_DIR=1
- DMS_DEBUG=0
cap_add:
- NET_ADMIN
volumes:
maildata:
driver: local
mailstate:
driver: local

View File

@ -43,6 +43,7 @@ SUBCOMMANDS:
email:
$0 email add <email> <password>
$0 email update <email> <password>
$0 email del <email>
$0 email list
@ -115,6 +116,10 @@ case $1 in
shift
_docker_image addmailuser $@
;;
update)
shift
_docker_image updatemailuser $@
;;
del)
shift
_docker_image delmailuser $@

View File

@ -1,29 +1,32 @@
#!/bin/bash
#! /bin/bash
DATABASE=/tmp/docker-mailserver/postfix-accounts.cf
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
function usage {
echo 'Usage: addmailuser <user@domain.tld> [password]'
USER="$1"
PASSWD="$2"
usage() {
echo "Usage: addmailuser <user@domain> [<password>]"
}
errex() {
echo "$@" 1>&2
exit 1
}
if [ ! -z "$1" ]; then
USER=$1
if [ -e "$DATABASE" ] && [ ! -z "$(grep $USER -i $DATABASE)" ]; then
echo "User already exists"
exit 1
fi
if [ ! -z "$2" ]; then
PASS="$2"
else
read -s -p "Enter Password: " PASS
if [ -z "$PASS" ]; then
echo "Password can't be empty"
exit 1
fi
fi
ENTRY=$(echo "$USER|$(doveadm pw -s SHA512-CRYPT -u "$USER" -p "$PASS")")
echo "$ENTRY" >> $DATABASE
else
usage
escape() {
echo "${1//./\\.}"
}
[ -z "$USER" ] && { usage; errex "no username specified"; }
grep -qi "^$(escape "$USER")|" $DATABASE 2>/dev/null &&
errex "User \"$USER\" already exists"
if [ -z "$PASSWD" ]; then
read -s -p "Enter Password: " PASSWD
echo
[ -z "$PASSWD" ] && errex "Password must not be empty"
fi
echo "$USER|$(doveadm pw -s SHA512-CRYPT -u "$USER" -p "$PASSWD")" >>$DATABASE

View File

@ -1,18 +1,24 @@
#!/bin/bash
#! /bin/bash
DATABASE=/tmp/docker-mailserver/postfix-accounts.cf
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
function usage {
echo "Usage: delmailuser <user@domain.tld>"
USER="$1"
usage() {
echo "Usage: delmailuser <user@domain>"
}
errex() {
echo "$@" 1>&2
exit 1
}
if [ ! -z "$1" ]; then
USER=$1
if [ -f "$DATABASE" ]; then
ENTRIES=$(grep "$USER" -vi $DATABASE)
echo "$ENTRIES" > $DATABASE
fi
else
usage
fi
escape() {
echo "${1//./\\.}"
}
[ -z "$USER" ] && { usage; errex "No user specifed"; }
[ -s "$DATABASE" ] || exit 0
# XXX $USER must not contain /s and other syntactic characters
sed -i "/^$(escape "$USER")|/d" $DATABASE

View File

@ -1,16 +1,13 @@
#! /bin/sh
#! /bin/bash
DATABASE=/tmp/docker-mailserver/postfix-accounts.cf
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
if [ ! -f "$DATABASE" ]; then
echo "The configuration file 'postfix-accounts.cf' doesn't exist. Until now no email addresses have been added."
errex() {
echo "$@" 1>&2
exit 1
fi
}
if [ ! -s "$DATABASE" ]; then
echo "No email addresses have been added."
exit 1
fi
cat "$DATABASE" | awk -F '|' '{print $1}'
[ -f $DATABASE ] || errex "No postfix-accounts.cf file"
[ -s $DATABASE ] || errex "Empty postfix-accounts.cf - no users have been added"
awk -F '|' '{ print $1; }' $DATABASE

27
target/bin/updatemailuser Executable file
View File

@ -0,0 +1,27 @@
#! /bin/bash
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
USER="$1"
PASSWD="$2"
usage() {
echo "Usage: updatemailuser <user@domain.tld> [password]"
}
errex() {
echo "$@" 1>&2
exit 1
}
escape() {
echo "${1//./\\.}"
}
[ -z "$USER" ] && { usage; errex "no username specified"; }
grep -qi "^$(escape "$USER")|" $DATABASE 2>/dev/null ||
errex "User \"$USER\" does not exist"
delmailuser "$USER"
addmailuser "$USER" "$PASSWD"

View File

@ -46,10 +46,10 @@ ssl_key = </etc/dovecot/private/dovecot.pem
#ssl_dh_parameters_length = 1024
# SSL protocols to use
ssl_protocols = TLSv1 TLSv1.1 TLSv1.2
ssl_protocols = !SSLv2 !SSLv3
# SSL ciphers to use
ssl_cipher_list = ECDHE+AESGCM ECDHE+AES DHE+AESGCM DHE+AES DES-CBC3-SHA
ssl_cipher_list = 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:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
# Prefer the server's order of ciphers over client's.
ssl_prefer_server_ciphers = yes

View File

@ -27,11 +27,11 @@ smtpd_use_tls=yes
smtp_tls_security_level = may
smtp_tls_loglevel = 1
tls_ssl_options = NO_COMPRESSION
tls_high_cipherlist=EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA
tls_high_cipherlist=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:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
smtpd_tls_protocols=!SSLv2,!SSLv3
smtp_tls_protocols=!SSLv2,!SSLv3
smtpd_tls_mandatory_ciphers = high
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
smtpd_tls_mandatory_protocols = !SSLv2,!SSLv3
smtpd_tls_exclude_ciphers = aNULL, LOW, EXP, MEDIUM, ADH, AECDH, MD5, DSS, ECDSA, CAMELLIA128, 3DES, CAMELLIA256, RSA+AES, eNULL
smtpd_tls_CApath = /etc/ssl/certs
smtp_tls_CApath = /etc/ssl/certs

View File

@ -7,7 +7,17 @@
# Example: DEFAULT_VARS["KEY"]="VALUE"
##########################################################################
declare -A DEFAULT_VARS
DEFAULT_VARS["ENABLE_CLAMAV"]="${ENABLE_CLAMAV:="0"}"
DEFAULT_VARS["ENABLE_SPAMASSASSIN"]="${ENABLE_SPAMASSASSIN:="0"}"
DEFAULT_VARS["ENABLE_POP3"]="${ENABLE_POP3:="0"}"
DEFAULT_VARS["ENABLE_FAIL2BAN"]="${ENABLE_FAIL2BAN:="0"}"
DEFAULT_VARS["ENABLE_MANAGESIEVE"]="${ENABLE_MANAGESIEVE:="0"}"
DEFAULT_VARS["ENABLE_FETCHMAIL"]="${ENABLE_FETCHMAIL:="0"}"
DEFAULT_VARS["ENABLE_LDAP"]="${ENABLE_LDAP:="0"}"
DEFAULT_VARS["ENABLE_SASLAUTHD"]="${ENABLE_SASLAUTHD:="0"}"
DEFAULT_VARS["SMTP_ONLY"]="${SMTP_ONLY:="0"}"
DEFAULT_VARS["VIRUSMAILS_DELETE_DELAY"]="${VIRUSMAILS_DELETE_DELAY:="7"}"
DEFAULT_VARS["DMS_DEBUG"]="${DMS_DEBUG:="0"}"
##########################################################################
# << DEFAULT VARS
##########################################################################
@ -34,7 +44,8 @@ DEFAULT_VARS["VIRUSMAILS_DELETE_DELAY"]="${VIRUSMAILS_DELETE_DELAY:="7"}"
# Implement them in the section-group: {check,setup,fix,start}
##########################################################################
function register_functions() {
notify 'taskgrp' 'Registering check,setup,fix,misc and start-daemons functions'
notify 'taskgrp' 'Initializing setup'
notify 'task' 'Registering check,setup,fix,misc and start-daemons functions'
################### >> check funcs
@ -62,6 +73,7 @@ function register_functions() {
if [ "$ENABLE_SASLAUTHD" = 1 ];then
_register_setup_function "_setup_saslauthd"
_register_setup_function "_setup_postfix_sasl"
fi
_register_setup_function "_setup_dkim"
@ -75,7 +87,10 @@ function register_functions() {
_register_setup_function "_setup_security_stack"
_register_setup_function "_setup_postfix_aliases"
_register_setup_function "_setup_postfix_vhost"
if [ ! -z "$AWS_SES_HOST" -a ! -z "$AWS_SES_USERPASS" ]; then
_register_setup_function "_setup_postfix_relay_amazon_ses"
fi
if [ "$ENABLE_POSTFIX_VIRTUAL_TRANSPORT" = 1 ]; then
_register_setup_function "_setup_postfix_virtual_transport"
@ -97,7 +112,8 @@ function register_functions() {
################### >> daemon funcs
_register_start_daemon "_start_daemons_sys"
_register_start_daemon "_start_daemons_cron"
_register_start_daemon "_start_daemons_rsyslog"
if [ "$ENABLE_ELK_FORWARDER" = 1 ]; then
_register_start_daemon "_start_daemons_filebeat"
@ -125,13 +141,11 @@ function register_functions() {
_register_start_daemon "_start_daemons_fetchmail"
fi
if ! [ "$DISABLE_CLAMAV" = 1 ]; then
if [ "$ENABLE_CLAMAV" = 1 ]; then
_register_start_daemon "_start_daemons_clamav"
fi
if ! [ "$DISABLE_AMAVIS" = 1 ]; then
_register_start_daemon "_start_daemons_amavis"
fi
################### << daemon funcs
}
##########################################################################
@ -195,45 +209,78 @@ function _register_misc_function() {
function notify () {
c_red="\e[0;31m"
c_green="\e[0;32m"
c_brown="\e[0;33m"
c_blue="\e[0;34m"
c_bold="\033[1m"
c_reset="\e[0m"
notification_type=$1
notification_msg=$2
notification_format=$3
msg=""
case "${notification_type}" in
'inf')
msg="${c_green} * ${c_reset}${notification_msg}"
;;
'err')
msg="${c_red} * ${c_reset}${notification_msg}"
;;
'warn')
msg="${c_blue} * ${c_reset}${notification_msg}"
;;
'task')
msg=" >>>> ${notification_msg}"
;;
'taskgrp')
msg="${c_bold}${notification_msg}${c_reset}"
;;
'task')
if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then
msg=" ${notification_msg}${c_reset}"
fi
;;
'inf')
if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then
msg="${c_green} * ${notification_msg}${c_reset}"
fi
;;
'started')
msg="${c_green} ${notification_msg}${c_reset}"
;;
'warn')
msg="${c_brown} * ${notification_msg}${c_reset}"
;;
'err')
msg="${c_red} * ${notification_msg}${c_reset}"
;;
'fatal')
msg="${c_bold} >>>> ${notification_msg} <<<<${c_reset}"
msg="${c_red}Error: ${notification_msg}${c_reset}"
;;
*)
msg=""
;;
esac
[[ ! -z "${msg}" ]] && echo -e "${msg}"
case "${notification_format}" in
'n')
options="-ne"
;;
*)
options="-e"
;;
esac
[[ ! -z "${msg}" ]] && echo $options "${msg}"
}
function defunc() {
notify 'fatal' "Please fix the failures. Exiting ..."
notify 'fatal' "Please fix your configuration. Exiting..."
exit 1
}
function display_startup_daemon() {
$1 &>/dev/null
res=$?
if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then
if [ $res = 0 ]; then
notify 'started' " [ OK ]"
else
echo "false"
notify 'err' " [ FAILED ]"
fi
fi
return $res
}
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# ! CARE --> DON'T CHANGE, except you know exactly what you are doing
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@ -247,7 +294,7 @@ function defunc() {
# Description: Place functions for initial check of container sanity
##########################################################################
function check() {
notify 'taskgrp' 'Checking configuration sanity:'
notify 'taskgrp' 'Checking configuration'
for _func in "${FUNCS_CHECK[@]}";do
$_func
[ $? != 0 ] && defunc
@ -257,11 +304,11 @@ function check() {
function _check_hostname() {
notify "task" "Check that hostname/domainname is provided (no default docker hostname) [$FUNCNAME]"
if ( ! echo $(hostname) | grep -E '^(\S+[.]\S+)$' ); then
if ( ! echo $(hostname) | grep -E '^(\S+[.]\S+)$' > /dev/null ); then
notify 'err' "Setting hostname/domainname is required"
return 1
else
notify 'inf' "Hostname has been set"
notify 'inf' "Hostname has been set to $(hostname)"
return 0
fi
}
@ -281,11 +328,9 @@ function _check_environment_variables() {
# Description: Place functions for functional configurations here
##########################################################################
function setup() {
notify 'taskgrp' 'Setting up the Container:'
notify 'taskgrp' 'Configuring mail server'
for _func in "${FUNCS_SETUP[@]}";do
$_func
[ $? != 0 ] && defunc
done
}
@ -295,14 +340,14 @@ function _setup_default_vars() {
for var in ${!DEFAULT_VARS[@]}; do
echo "export $var=${DEFAULT_VARS[$var]}" >> /root/.bashrc
[ $? != 0 ] && notify 'err' "Unable to set $var=${DEFAULT_VARS[$var]}" && return 1
notify 'inf' "$var=${DEFAULT_VARS[$var]} set"
notify 'inf' "Set $var=${DEFAULT_VARS[$var]}"
done
}
function _setup_mailname() {
notify 'task' 'Setting up Mailname'
echo "Creating /etc/mailname"
notify 'inf' "Creating /etc/mailname"
echo $(hostname -d) > /etc/mailname
}
@ -321,7 +366,7 @@ function _setup_dovecot() {
# Enable Managesieve service by setting the symlink
# to the configuration file Dovecot will actually find
if [ "$ENABLE_MANAGESIEVE" = 1 ]; then
echo "Sieve management enabled"
notify 'inf' "Sieve management enabled"
mv /etc/dovecot/protocols.d/managesieved.protocol.disab /etc/dovecot/protocols.d/managesieved.protocol
fi
}
@ -331,9 +376,9 @@ function _setup_dovecot_local_user() {
echo -n > /etc/postfix/vmailbox
echo -n > /etc/dovecot/userdb
if [ -f /tmp/docker-mailserver/postfix-accounts.cf -a "$ENABLE_LDAP" != 1 ]; then
echo "Checking file line endings"
notify 'inf' "Checking file line endings"
sed -i 's/\r//g' /tmp/docker-mailserver/postfix-accounts.cf
echo "Regenerating postfix 'vmailbox' and 'virtual' for given users"
notify 'inf' "Regenerating postfix user list"
echo "# WARNING: this file is auto-generated. Modify config/postfix-accounts.cf to edit user list." > /etc/postfix/vmailbox
# Checking that /tmp/docker-mailserver/postfix-accounts.cf ends with a newline
@ -353,7 +398,7 @@ function _setup_dovecot_local_user() {
user=$(echo ${login} | cut -d @ -f1)
domain=$(echo ${login} | cut -d @ -f2)
# Let's go!
echo "user '${user}' for domain '${domain}' with password '********'"
notify 'inf' "user '${user}' for domain '${domain}' with password '********'"
echo "${login} ${domain}/${user}/" >> /etc/postfix/vmailbox
# User database for dovecot has the following format:
# user:password:uid:gid:(gecos):home:(shell):extra_fields
@ -374,7 +419,7 @@ function _setup_dovecot_local_user() {
echo ${domain} >> /tmp/vhost.tmp
done < /tmp/docker-mailserver/postfix-accounts.cf
else
echo "==> Warning: 'config/docker-mailserver/postfix-accounts.cf' is not provided. No mail account created."
notify 'warn' "'config/docker-mailserver/postfix-accounts.cf' is not provided. No mail account created."
fi
}
@ -388,7 +433,7 @@ function _setup_ldap() {
/etc/postfix/ldap-${i}.cf
done
echo "Configuring dovecot LDAP authentification"
notify 'inf' "Configuring dovecot LDAP authentification"
sed -i -e 's|^hosts.*|hosts = '${LDAP_SERVER_HOST:="mail.domain.com"}'|g' \
-e 's|^base.*|base = '${LDAP_SEARCH_BASE:="ou=people,dc=domain,dc=com"}'|g' \
-e 's|^dn\s*=.*|dn = '${LDAP_BIND_DN:="cn=admin,dc=domain,dc=com"}'|g' \
@ -398,39 +443,43 @@ function _setup_ldap() {
# Add domainname to vhost.
echo $(hostname -d) >> /tmp/vhost.tmp
echo "Enabling dovecot LDAP authentification"
notify 'inf' "Enabling dovecot LDAP authentification"
sed -i -e '/\!include auth-ldap\.conf\.ext/s/^#//' /etc/dovecot/conf.d/10-auth.conf
sed -i -e '/\!include auth-passwdfile\.inc/s/^/#/' /etc/dovecot/conf.d/10-auth.conf
echo "Configuring LDAP"
notify 'inf' "Configuring LDAP"
[ -f /etc/postfix/ldap-users.cf ] && \
postconf -e "virtual_mailbox_maps = ldap:/etc/postfix/ldap-users.cf" || \
echo '==> Warning: /etc/postfix/ldap-user.cf not found'
notify 'inf' "==> Warning: /etc/postfix/ldap-user.cf not found"
[ -f /etc/postfix/ldap-aliases.cf -a -f /etc/postfix/ldap-groups.cf ] && \
postconf -e "virtual_alias_maps = ldap:/etc/postfix/ldap-aliases.cf, ldap:/etc/postfix/ldap-groups.cf" || \
echo '==> Warning: /etc/postfix/ldap-aliases.cf or /etc/postfix/ldap-groups.cf not found'
notify 'inf' "==> Warning: /etc/postfix/ldap-aliases.cf or /etc/postfix/ldap-groups.cf not found"
return 0
}
function _setup_postfix_sasl() {
[ ! -f /etc/postfix/sasl/smtpd.conf ] && cat > /etc/postfix/sasl/smtpd.conf << EOF
pwcheck_method: saslauthd
mech_list: plain login
EOF
return 0
return 0
}
function _setup_saslauthd() {
notify 'task' 'Setting up Saslauthd'
notify 'task' "Setting up Saslauthd"
echo "Configuring Cyrus SASL"
notify 'inf' "Configuring Cyrus SASL"
# checking env vars and setting defaults
[ -z $SASLAUTHD_MECHANISMS ] && SASLAUTHD_MECHANISMS=pam
[ -z $SASLAUTHD_LDAP_SEARCH_BASE ] && SASLAUTHD_MECHANISMS=pam
[ "$SASLAUTHD_MECHANISMS" = ldap -a -z $SASLAUTHD_LDAP_SEARCH_BASE ] && SASLAUTHD_MECHANISMS=pam
[ -z $SASLAUTHD_LDAP_SERVER ] && SASLAUTHD_LDAP_SERVER=localhost
[ -z $SASLAUTHD_LDAP_FILTER ] && SASLAUTHD_LDAP_FILTER='(&(uniqueIdentifier=%u)(mailEnabled=TRUE))'
([ -z $SASLAUTHD_LDAP_SSL ] || [ $SASLAUTHD_LDAP_SSL == 0 ]) && SASLAUTHD_LDAP_PROTO='ldap://' || SASLAUTHD_LDAP_PROTO='ldaps://'
if [ ! -f /etc/saslauthd.conf ]; then
echo "Creating /etc/saslauthd.conf"
notify 'inf' "Creating /etc/saslauthd.conf"
cat > /etc/saslauthd.conf << EOF
ldap_servers: ${SASLAUTHD_LDAP_PROTO}${SASLAUTHD_LDAP_SERVER}
@ -456,6 +505,13 @@ EOF
-e "s|^MECHANISMS=.*|MECHANISMS="\"$SASLAUTHD_MECHANISMS\""|g" \
-e "s|^MECH_OPTIONS=.*|MECH_OPTIONS="\"$SASLAUTHD_MECH_OPTIONS\""|g" \
/etc/default/saslauthd
if [ "$SASLAUTHD_MECHANISMS" = rimap ]; then
sed -i \
-e 's|^OPTIONS="|OPTIONS="-r |g' \
/etc/default/saslauthd
fi
sed -i \
-e "/smtpd_sasl_path =.*/d" \
-e "/smtpd_sasl_type =.*/d" \
@ -481,11 +537,11 @@ function _setup_postfix_aliases() {
test "$uname" != "$domain" && echo ${domain} >> /tmp/vhost.tmp
done < /tmp/docker-mailserver/postfix-virtual.cf
else
echo "==> Warning: 'config/postfix-virtual.cf' is not provided. No mail alias/forward created."
notify 'inf' "Warning 'config/postfix-virtual.cf' is not provided. No mail alias/forward created."
fi
if [ -f /tmp/docker-mailserver/postfix-regexp.cf ]; then
# Copying regexp alias file
echo "Adding regexp alias file postfix-regexp.cf"
notify 'inf' "Adding regexp alias file postfix-regexp.cf"
cp -f /tmp/docker-mailserver/postfix-regexp.cf /etc/postfix/regexp
sed -i -e '/^virtual_alias_maps/{
s/ regexp:.*//
@ -497,18 +553,18 @@ function _setup_postfix_aliases() {
function _setup_dkim() {
notify 'task' 'Setting up DKIM'
mkdir -p /etc/opendkim && touch /etc/opendkim/SigningTable
# Check if keys are already available
if [ -e "/tmp/docker-mailserver/opendkim/KeyTable" ]; then
mkdir -p /etc/opendkim
cp -a /tmp/docker-mailserver/opendkim/* /etc/opendkim/
echo "DKIM keys added for: `ls -C /etc/opendkim/keys/`"
echo "Changing permissions on /etc/opendkim"
# chown entire directory
notify 'inf' "DKIM keys added for: `ls -C /etc/opendkim/keys/`"
notify 'inf' "Changing permissions on /etc/opendkim"
chown -R opendkim:opendkim /etc/opendkim/
# And make sure permissions are right
chmod -R 0700 /etc/opendkim/keys/
else
echo "No DKIM key provided. Check the documentation to find how to get your keys."
notify 'warn' "No DKIM key provided. Check the documentation to find how to get your keys."
fi
}
@ -528,7 +584,7 @@ function _setup_ssl() {
KEY="key"
fi
if [ -n "$KEY" ]; then
echo "Adding $(hostname) SSL certificate"
notify 'inf' "Adding $(hostname) SSL certificate"
# Postfix configuration
sed -i -r 's~smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem~smtpd_tls_cert_file=/etc/letsencrypt/live/'$(hostname)'/fullchain.pem~g' /etc/postfix/main.cf
@ -538,14 +594,14 @@ function _setup_ssl() {
sed -i -e 's~ssl_cert = </etc/dovecot/dovecot\.pem~ssl_cert = </etc/letsencrypt/live/'$(hostname)'/fullchain\.pem~g' /etc/dovecot/conf.d/10-ssl.conf
sed -i -e 's~ssl_key = </etc/dovecot/private/dovecot\.pem~ssl_key = </etc/letsencrypt/live/'$(hostname)'/'"$KEY"'\.pem~g' /etc/dovecot/conf.d/10-ssl.conf
echo "SSL configured with 'letsencrypt' certificates"
notify 'inf' "SSL configured with 'letsencrypt' certificates"
fi
fi
;;
"custom" )
# Adding CA signed SSL certificate if provided in 'postfix/ssl' folder
if [ -e "/tmp/docker-mailserver/ssl/$(hostname)-full.pem" ]; then
echo "Adding $(hostname) SSL certificate"
notify 'inf' "Adding $(hostname) SSL certificate"
mkdir -p /etc/postfix/ssl
cp "/tmp/docker-mailserver/ssl/$(hostname)-full.pem" /etc/postfix/ssl
@ -557,14 +613,14 @@ function _setup_ssl() {
sed -i -e 's~ssl_cert = </etc/dovecot/dovecot\.pem~ssl_cert = </etc/postfix/ssl/'$(hostname)'-full\.pem~g' /etc/dovecot/conf.d/10-ssl.conf
sed -i -e 's~ssl_key = </etc/dovecot/private/dovecot\.pem~ssl_key = </etc/postfix/ssl/'$(hostname)'-full\.pem~g' /etc/dovecot/conf.d/10-ssl.conf
echo "SSL configured with 'CA signed/custom' certificates"
notify 'inf' "SSL configured with 'CA signed/custom' certificates"
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" ]; then
echo "Configuring certificates using cert $SSL_CERT_PATH and key $SSL_KEY_PATH"
notify 'inf' "Configuring certificates using cert $SSL_CERT_PATH and key $SSL_KEY_PATH"
mkdir -p /etc/postfix/ssl
cp "$SSL_CERT_PATH" /etc/postfix/ssl/cert
cp "$SSL_KEY_PATH" /etc/postfix/ssl/key
@ -579,7 +635,7 @@ function _setup_ssl() {
sed -i -e 's~ssl_cert = </etc/dovecot/dovecot\.pem~ssl_cert = </etc/postfix/ssl/cert~g' /etc/dovecot/conf.d/10-ssl.conf
sed -i -e 's~ssl_key = </etc/dovecot/private/dovecot\.pem~ssl_key = </etc/postfix/ssl/key~g' /etc/dovecot/conf.d/10-ssl.conf
echo "SSL configured with 'Manual' certificates"
notify 'inf' "SSL configured with 'Manual' certificates"
fi
;;
"self-signed" )
@ -588,7 +644,7 @@ function _setup_ssl() {
&& [ -e "/tmp/docker-mailserver/ssl/$(hostname)-key.pem" ] \
&& [ -e "/tmp/docker-mailserver/ssl/$(hostname)-combined.pem" ] \
&& [ -e "/tmp/docker-mailserver/ssl/demoCA/cacert.pem" ]; then
echo "Adding $(hostname) SSL certificate"
notify 'inf' "Adding $(hostname) SSL certificate"
mkdir -p /etc/postfix/ssl
cp "/tmp/docker-mailserver/ssl/$(hostname)-cert.pem" /etc/postfix/ssl
cp "/tmp/docker-mailserver/ssl/$(hostname)-key.pem" /etc/postfix/ssl
@ -608,7 +664,7 @@ function _setup_ssl() {
sed -i -e 's~ssl_cert = </etc/dovecot/dovecot\.pem~ssl_cert = </etc/postfix/ssl/'$(hostname)'-combined\.pem~g' /etc/dovecot/conf.d/10-ssl.conf
sed -i -e 's~ssl_key = </etc/dovecot/private/dovecot\.pem~ssl_key = </etc/postfix/ssl/'$(hostname)'-key\.pem~g' /etc/dovecot/conf.d/10-ssl.conf
echo "SSL configured with 'self-signed' certificates"
notify 'inf' "SSL configured with 'self-signed' certificates"
fi
;;
esac
@ -630,30 +686,26 @@ function _setup_docker_permit() {
case $PERMIT_DOCKER in
"host" )
echo "Adding $container_network/16 to my networks"
notify 'inf' "Adding $container_network/16 to my networks"
postconf -e "$(postconf | grep '^mynetworks =') $container_network/16"
bash -c "echo $container_network/16 >> /etc/opendmarc/ignore.hosts"
bash -c "echo $container_network/16 >> /etc/opendkim/TrustedHosts"
echo $container_network/16 >> /etc/opendmarc/ignore.hosts
echo $container_network/16 >> /etc/opendkim/TrustedHosts
;;
"network" )
echo "Adding docker network in my networks"
notify 'inf' "Adding docker network in my networks"
postconf -e "$(postconf | grep '^mynetworks =') 172.16.0.0/12"
bash -c "echo 172.16.0.0/12 >> /etc/opendmarc/ignore.hosts"
bash -c "echo 172.16.0.0/12 >> /etc/opendkim/TrustedHosts"
echo 172.16.0.0/12 >> /etc/opendmarc/ignore.hosts
echo 172.16.0.0/12 >> /etc/opendkim/TrustedHosts
;;
* )
echo "Adding container ip in my networks"
notify 'inf' "Adding container ip in my networks"
postconf -e "$(postconf | grep '^mynetworks =') $container_ip/32"
bash -c "echo $container_ip/32 >> /etc/opendmarc/ignore.hosts"
bash -c "echo $container_ip/32 >> /etc/opendkim/TrustedHosts"
echo $container_ip/32 >> /etc/opendmarc/ignore.hosts
echo $container_ip/32 >> /etc/opendkim/TrustedHosts
;;
esac
# @TODO fix: bash: /etc/opendkim/TrustedHosts: No such file or directory
# temporary workarround return success
return 0
}
function _setup_postfix_virtual_transport() {
@ -672,9 +724,9 @@ function _setup_postfix_override_configuration() {
while read line; do
postconf -e "$line"
done < /tmp/docker-mailserver/postfix-main.cf
echo "Loaded 'config/postfix-main.cf'"
notify 'inf' "Loaded 'config/postfix-main.cf'"
else
echo "No extra postfix settings loaded because optional '/tmp/docker-mailserver/postfix-main.cf' not provided."
notify 'inf' "No extra postfix settings loaded because optional '/tmp/docker-mailserver/postfix-main.cf' not provided."
fi
}
@ -691,20 +743,18 @@ function _setup_postfix_sasl_password() {
if [ -f /etc/postfix/sasl_passwd ]; then
chown root:root /etc/postfix/sasl_passwd
chmod 0600 /etc/postfix/sasl_passwd
echo "Loaded SASL_PASSWD"
notify 'inf' "Loaded SASL_PASSWD"
else
echo "==> Warning: 'SASL_PASSWD' is not provided. /etc/postfix/sasl_passwd not created."
notify 'inf' "Warning: 'SASL_PASSWD' is not provided. /etc/postfix/sasl_passwd not created."
fi
}
function _setup_postfix_relay_amazon_ses() {
notify 'task' 'Setting up Postfix Relay Amazon SES'
if [ ! -z "$AWS_SES_HOST" -a ! -z "$AWS_SES_USERPASS" ]; then
if [ -z "$AWS_SES_PORT" ];then
AWS_SES_PORT=25
fi
echo "Setting up outgoing email via AWS SES host $AWS_SES_HOST:$AWS_SES_PORT"
notify 'inf' "Setting up outgoing email via AWS SES host $AWS_SES_HOST:$AWS_SES_PORT"
echo "[$AWS_SES_HOST]:$AWS_SES_PORT $AWS_SES_USERPASS" >> /etc/postfix/sasl_passwd
postconf -e \
"relayhost = [$AWS_SES_HOST]:$AWS_SES_PORT" \
@ -715,21 +765,42 @@ function _setup_postfix_relay_amazon_ses() {
"smtp_tls_security_level = encrypt" \
"smtp_tls_note_starttls_offer = yes" \
"smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt"
fi
}
function _setup_security_stack() {
notify 'task' 'Setting up Security Stack'
notify 'task' "Setting up Security Stack"
echo "Configuring Spamassassin"
# recreate auto-generated file
dms_amavis_file="/etc/amavis/conf.d/51-dms_auto_generated"
echo "# WARNING: this file is auto-generated." > $dms_amavis_file
echo "use strict;" >> $dms_amavis_file
# Spamassassin
if [ "$ENABLE_SPAMASSASSIN" = 0 ]; then
notify 'warn' "Spamassassin is disabled. You can enable it with 'ENABLE_SPAMASSASSIN=1'"
echo "@bypass_spam_checks_maps = (1);" >> $dms_amavis_file
elif [ "$ENABLE_SPAMASSASSIN" = 1 ]; then
notify 'inf' "Enabling and configuring spamassassin"
SA_TAG=${SA_TAG:="2.0"} && sed -i -r 's/^\$sa_tag_level_deflt (.*);/\$sa_tag_level_deflt = '$SA_TAG';/g' /etc/amavis/conf.d/20-debian_defaults
SA_TAG2=${SA_TAG2:="6.31"} && sed -i -r 's/^\$sa_tag2_level_deflt (.*);/\$sa_tag2_level_deflt = '$SA_TAG2';/g' /etc/amavis/conf.d/20-debian_defaults
SA_KILL=${SA_KILL:="6.31"} && sed -i -r 's/^\$sa_kill_level_deflt (.*);/\$sa_kill_level_deflt = '$SA_KILL';/g' /etc/amavis/conf.d/20-debian_defaults
test -e /tmp/docker-mailserver/spamassassin-rules.cf && cp /tmp/docker-mailserver/spamassassin-rules.cf /etc/spamassassin/
fi
# Clamav
if [ "$ENABLE_CLAMAV" = 0 ]; then
notify 'warn' "Clamav is disabled. You can enable it with 'ENABLE_CLAMAV=1'"
echo "@bypass_virus_checks_maps = (1);" >> $dms_amavis_file
elif [ "$ENABLE_CLAMAV" = 1 ]; then
notify 'inf' "Enabling clamav"
fi
echo "1; # ensure a defined return" >> $dms_amavis_file
# Fail2ban
if [ "$ENABLE_FAIL2BAN" = 1 ]; then
echo "Fail2ban enabled"
notify 'inf' "Fail2ban enabled"
test -e /tmp/docker-mailserver/fail2ban-jail.cf && cp /tmp/docker-mailserver/fail2ban-jail.cf /etc/fail2ban/jail.local
else
# Disable logrotate config for fail2ban if not enabled
@ -750,7 +821,7 @@ function _setup_elk_forwarder() {
ELK_PORT=${ELK_PORT:="5044"}
ELK_HOST=${ELK_HOST:="elk"}
echo "Enabling log forwarding to ELK ($ELK_HOST:$ELK_PORT)"
notify 'inf' "Enabling log forwarding to ELK ($ELK_HOST:$ELK_PORT)"
cat /etc/filebeat/filebeat.yml.tmpl \
| sed "s@\$ELK_HOST@$ELK_HOST@g" \
| sed "s@\$ELK_PORT@$ELK_PORT@g" \
@ -767,7 +838,7 @@ function _setup_elk_forwarder() {
# Description: Place functions for temporary workarounds and fixes here
##########################################################################
function fix() {
notify 'taskgrg' "Starting to fix:"
notify 'taskgrg' "Post-configuration checks..."
for _func in "${FUNCS_FIX[@]}";do
$_func
[ $? != 0 ] && defunc
@ -779,10 +850,11 @@ function _fix_var_mail_permissions() {
# Fix permissions, but skip this if 3 levels deep the user id is already set
if [ `find /var/mail -maxdepth 3 -a \( \! -user 5000 -o \! -group 5000 \) | grep -c .` != 0 ]; then
notify 'inf' "Fixing /var/mail permissions"
chown -R 5000:5000 /var/mail
echo "/var/mail permissions fixed"
else
echo "Permissions in /var/mail look OK"
notify 'inf' "Permissions in /var/mail look OK"
return 0
fi
}
##########################################################################
@ -796,7 +868,7 @@ function _fix_var_mail_permissions() {
# Description: Place functions that do not fit in the sections above here
##########################################################################
function misc() {
notify 'taskgrp' 'Starting Misc:'
notify 'taskgrp' 'Starting Misc'
for _func in "${FUNCS_MISC[@]}";do
$_func
@ -809,19 +881,19 @@ function _misc_save_states() {
# directory
statedir=/var/mail-state
if [ "$ONE_DIR" = 1 -a -d $statedir ]; then
echo "Consolidating all state onto $statedir"
notify 'inf' "Consolidating all state onto $statedir"
for d in /var/spool/postfix /var/lib/postfix /var/lib/amavis /var/lib/clamav /var/lib/spamassasin /var/lib/fail2ban; do
dest=$statedir/`echo $d | sed -e 's/.var.//; s/\//-/g'`
if [ -d $dest ]; then
echo " Destination $dest exists, linking $d to it"
notify 'inf' " Destination $dest exists, linking $d to it"
rm -rf $d
ln -s $dest $d
elif [ -d $d ]; then
echo " Moving contents of $d to $dest:" `ls $d`
notify 'inf' " Moving contents of $d to $dest:" `ls $d`
mv $d $dest
ln -s $dest $d
else
echo " Linking $d to $dest"
notify 'inf' " Linking $d to $dest"
mkdir -p $dest
ln -s $dest $d
fi
@ -834,7 +906,7 @@ function _misc_save_states() {
# >> Start Daemons
##########################################################################
function start_daemons() {
notify 'taskgrp' 'Starting Daemons'
notify 'taskgrp' 'Starting mail server'
for _func in "${DAEMONS_START[@]}";do
$_func
@ -842,57 +914,58 @@ function start_daemons() {
done
}
function _start_daemons_sys() {
notify 'task' 'Starting Cron'
cron
function _start_daemons_cron() {
notify 'task' 'Starting cron' 'n'
display_startup_daemon "cron"
}
notify 'task' 'Starting rsyslog'
/etc/init.d/rsyslog start
function _start_daemons_rsyslog() {
notify 'task' 'Starting rsyslog' 'n'
display_startup_daemon "/etc/init.d/rsyslog start"
}
function _start_daemons_saslauthd() {
notify "task" "Starting saslauthd"
/etc/init.d/saslauthd start
notify 'task' 'Starting saslauthd' 'n'
display_startup_daemon "/etc/init.d/saslauthd start"
}
function _start_daemons_fail2ban() {
notify 'task' 'Starting fail2ban'
notify 'task' 'Starting fail2ban' 'n'
touch /var/log/auth.log
# Delete fail2ban.sock that probably was left here after container restart
if [ -e /var/run/fail2ban/fail2ban.sock ]; then
rm /var/run/fail2ban/fail2ban.sock
fi
/etc/init.d/fail2ban start
display_startup_daemon "/etc/init.d/fail2ban start"
}
function _start_daemons_opendkim() {
notify 'task' 'Starting opendkim'
/etc/init.d/opendkim start
notify 'task' 'Starting opendkim' 'n'
display_startup_daemon "/etc/init.d/opendkim start"
}
function _start_daemons_opendmarc() {
notify 'task' 'Starting opendmarc'
/etc/init.d/opendmarc start
notify 'task' 'Starting opendmarc' 'n'
display_startup_daemon "/etc/init.d/opendmarc start"
}
function _start_daemons_postfix() {
notify 'task' 'Starting postfix'
/etc/init.d/postfix start
notify 'task' 'Starting postfix' 'n'
display_startup_daemon "/etc/init.d/postfix start"
}
function _start_daemons_dovecot() {
# Here we are starting sasl and imap, not pop3 because it's disabled by default
notify 'task' "Starting dovecot services"
/usr/sbin/dovecot -c /etc/dovecot/dovecot.conf
notify 'task' 'Starting dovecot services' 'n'
display_startup_daemon "/usr/sbin/dovecot -c /etc/dovecot/dovecot.conf"
if [ "$ENABLE_POP3" = 1 ]; then
echo "Starting POP3 services"
notify 'task' 'Starting pop3 services' 'n'
mv /etc/dovecot/protocols.d/pop3d.protocol.disab /etc/dovecot/protocols.d/pop3d.protocol
/usr/sbin/dovecot reload
display_startup_daemon "/usr/sbin/dovecot reload"
fi
if [ -f /tmp/docker-mailserver/dovecot.cf ]; then
echo 'Adding file "dovecot.cf" to the Dovecot configuration'
cp /tmp/docker-mailserver/dovecot.cf /etc/dovecot/local.conf
/usr/sbin/dovecot reload
fi
@ -908,25 +981,24 @@ function _start_daemons_dovecot() {
}
function _start_daemons_filebeat() {
notify 'task' 'Starting FileBeat'
/etc/init.d/filebeat start
notify 'task' 'Starting filebeat' 'n'
display_startup_daemon "/etc/init.d/filebeat start"
}
function _start_daemons_fetchmail() {
notify 'task' 'Starting fetchmail'
notify 'task' 'Starting fetchmail' 'n'
/usr/local/bin/setup-fetchmail
echo "Fetchmail enabled"
/etc/init.d/fetchmail start
display_startup_daemon "/etc/init.d/fetchmail start"
}
function _start_daemons_clamav() {
notify 'task' "Starting clamav"
/etc/init.d/clamav-daemon start
notify 'task' 'Starting clamav' 'n'
display_startup_daemon "/etc/init.d/clamav-daemon start"
}
function _start_daemons_amavis() {
notify 'task' 'Starting Daemon Amavis'
/etc/init.d/amavis start
notify 'task' 'Starting amavis' 'n'
display_startup_daemon "/etc/init.d/amavis start"
# @TODO fix: on integration test of mail_with_ldap amavis fails because of:
# Starting amavisd: The value of variable $myhostname is "ldap", but should have been
@ -935,7 +1007,7 @@ function _start_daemons_amavis() {
# in /etc/amavis/conf.d/05-node_id, or fix what uname(3) provides as a host's
# network name!
# > temporary workaround to passe integration test
# > temporary workaround to pass integration test
return 0
}
##########################################################################
@ -951,6 +1023,24 @@ function _start_daemons_amavis() {
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# >>
if [[ ${DEFAULT_VARS["DMS_DEBUG"]} == 1 ]]; then
notify 'taskgrp' ""
notify 'taskgrp' "#"
notify 'taskgrp' "#"
notify 'taskgrp' "# ENV"
notify 'taskgrp' "#"
notify 'taskgrp' "#"
notify 'taskgrp' ""
printenv
fi
notify 'taskgrp' ""
notify 'taskgrp' "#"
notify 'taskgrp' "#"
notify 'taskgrp' "# docker-mailserver"
notify 'taskgrp' "#"
notify 'taskgrp' "#"
notify 'taskgrp' ""
register_functions
@ -960,7 +1050,14 @@ fix
misc
start_daemons
tail -f /var/log/mail/mail.log
notify 'taskgrp' ""
notify 'taskgrp' "#"
notify 'taskgrp' "# $(hostname) is up and running"
notify 'taskgrp' "#"
notify 'taskgrp' ""
tail -fn 0 /var/log/mail/mail.log
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

View File

@ -56,13 +56,8 @@
[ "$status" -eq 0 ]
}
@test "checking process: amavis (amavis disabled by DISABLE_AMAVIS)" {
run docker exec mail_disabled_amavis /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/amavisd-new'"
[ "$status" -eq 1 ]
}
@test "checking process: clamav (clamav disabled by DISABLE_CLAMAV)" {
run docker exec mail_disabled_clamav /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/clamd'"
@test "checking process: clamav (clamav disabled by ENABLED_CLAMAV=0)" {
run docker exec mail_disabled_clamav_spamassassin /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/clamd'"
[ "$status" -eq 1 ]
}
@ -71,6 +66,11 @@
[ "$status" -eq 0 ]
}
@test "checking process: saslauthd (saslauthd server enabled)" {
run docker exec mail_with_imap /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/sbin/saslauthd'"
[ "$status" -eq 0 ]
}
#
# imap
#
@ -274,6 +274,16 @@
# spamassassin
#
@test "checking spamassassin: should be listed in amavis when enabled" {
run docker exec mail /bin/sh -c "grep -i 'ANTI-SPAM-SA code' /var/log/mail/mail.log | grep 'NOT loaded'"
[ "$status" -eq 1 ]
}
@test "checking spamassassin: should not be listed in amavis when disabled" {
run docker exec mail_disabled_clamav_spamassassin /bin/sh -c "grep -i 'ANTI-SPAM-SA code' /var/log/mail/mail.log | grep 'NOT loaded'"
[ "$status" -eq 0 ]
}
@test "checking spamassassin: docker env variables are set correctly (default)" {
run docker exec mail_pop3 /bin/sh -c "grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'"
[ "$status" -eq 0 ]
@ -292,6 +302,25 @@
[ "$status" -eq 0 ]
}
#
# clamav
#
@test "checking clamav: should be listed in amavis when enabled" {
run docker exec mail grep -i 'Found secondary av scanner ClamAV-clamscan' /var/log/mail/mail.log
[ "$status" -eq 0 ]
}
@test "checking clamav: should not be listed in amavis when disabled" {
run docker exec mail_disabled_clamav_spamassassin grep -i 'Found secondary av scanner ClamAV-clamscan' /var/log/mail/mail.log
[ "$status" -eq 1 ]
}
@test "checking clamav: should not be called when disabled" {
run docker exec mail_disabled_clamav_spamassassin grep -i 'connect to /var/run/clamav/clamd.ctl failed' /var/log/mail/mail.log
[ "$status" -eq 1 ]
}
#
# opendkim
#
@ -402,13 +431,8 @@
[ "$status" -eq 0 ]
}
@test "checking ssl: lets-encrypt-x1-cross-signed.pem is installed" {
run docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem
[ "$status" -eq 0 ]
}
@test "checking ssl: lets-encrypt-x2-cross-signed.pem is installed" {
run docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-encrypt-x2-cross-signed.pem
@test "checking ssl: lets-encrypt-x3-cross-signed.pem is installed" {
run docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-encrypt-x3-cross-signed.pem
[ "$status" -eq 0 ]
}
@ -483,7 +507,7 @@
# Getting mail_fail2ban container IP
MAIL_FAIL2BAN_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' mail_fail2ban)
# Create a container which will send wront authentications and should banned
# Create a container which will send wrong authentications and should banned
docker run --name fail-auth-mailer -e MAIL_FAIL2BAN_IP=$MAIL_FAIL2BAN_IP -v "$(pwd)/test":/tmp/docker-mailserver-test -d $(docker inspect --format '{{ .Config.Image }}' mail) tail -f /var/log/faillog
docker exec fail-auth-mailer /bin/sh -c 'nc $MAIL_FAIL2BAN_IP 25 < /tmp/docker-mailserver-test/auth/smtp-auth-login-wrong.txt'
@ -577,6 +601,8 @@
[ "$status" -eq 1 ]
run docker exec mail grep -i 'permission denied' /var/log/mail/mail.log
[ "$status" -eq 1 ]
run docker exec mail grep -i '(!)connect' /var/log/mail/mail.log
[ "$status" -eq 1 ]
run docker exec mail_pop3 grep 'non-null host address bits in' /var/log/mail/mail.log
[ "$status" -eq 1 ]
run docker exec mail_pop3 grep ': error:' /var/log/mail/mail.log
@ -632,19 +658,60 @@
@test "checking accounts: user3 should have been added to /tmp/docker-mailserver/postfix-accounts.cf" {
docker exec mail /bin/sh -c "addmailuser user3@domain.tld mypassword"
run docker exec mail /bin/sh -c "grep user3@domain.tld -i /tmp/docker-mailserver/postfix-accounts.cf"
run docker exec mail /bin/sh -c "grep '^user3@domain\.tld|' -i /tmp/docker-mailserver/postfix-accounts.cf"
[ "$status" -eq 0 ]
[ ! -z "$output" ]
}
@test "checking accounts: user3 should have been removed from /tmp/docker-mailserver/postfix-accounts.cf" {
@test "checking accounts: auser3 should have been added to /tmp/docker-mailserver/postfix-accounts.cf" {
docker exec mail /bin/sh -c "addmailuser auser3@domain.tld mypassword"
run docker exec mail /bin/sh -c "grep '^auser3@domain\.tld|' -i /tmp/docker-mailserver/postfix-accounts.cf"
[ "$status" -eq 0 ]
[ ! -z "$output" ]
}
@test "checking accounts: a.ser3 should have been added to /tmp/docker-mailserver/postfix-accounts.cf" {
docker exec mail /bin/sh -c "addmailuser a.ser3@domain.tld mypassword"
run docker exec mail /bin/sh -c "grep '^a\.ser3@domain\.tld|' -i /tmp/docker-mailserver/postfix-accounts.cf"
[ "$status" -eq 0 ]
[ ! -z "$output" ]
}
@test "checking accounts: user3 should have been removed from /tmp/docker-mailserver/postfix-accounts.cf but not auser3" {
docker exec mail /bin/sh -c "delmailuser user3@domain.tld"
run docker exec mail /bin/sh -c "grep user3@domain.tld -i /tmp/docker-mailserver/postfix-accounts.cf"
run docker exec mail /bin/sh -c "grep '^user3@domain\.tld' -i /tmp/docker-mailserver/postfix-accounts.cf"
[ "$status" -eq 1 ]
[ -z "$output" ]
run docker exec mail /bin/sh -c "grep '^auser3@domain\.tld' -i /tmp/docker-mailserver/postfix-accounts.cf"
[ "$status" -eq 0 ]
[ ! -z "$output" ]
}
@test "checking user updating password for user in /tmp/docker-mailserver/postfix-accounts.cf" {
docker exec mail /bin/sh -c "addmailuser user4@domain.tld mypassword"
initialpass=$(run docker exec mail /bin/sh -c "grep '^user4@domain\.tld' -i /tmp/docker-mailserver/postfix-accounts.cf")
sleep 2
docker exec mail /bin/sh -c "updatemailuser user4@domain.tld mynewpassword"
sleep 2
changepass=$(run docker exec mail /bin/sh -c "grep '^user4@domain\.tld' -i /tmp/docker-mailserver/postfix-accounts.cf")
if [ initialpass != changepass ]; then
status="0"
else
status="1"
fi
docker exec mail /bin/sh -c "delmailuser auser3@domain.tld"
[ "$status" -eq 0 ]
}
@test "checking accounts: listmailuser" {
run docker exec mail /bin/sh -c "listmailuser | head -n 1"
[ "$status" -eq 0 ]
@ -663,6 +730,7 @@
run docker run --rm \
-v "$(pwd)/test/config/without-accounts/":/tmp/docker-mailserver/ \
`docker inspect --format '{{ .Config.Image }}' mail` /bin/sh -c 'addmailuser user3@domain.tld mypassword'
[ "$status" -eq 0 ]
run docker run --rm \
-v "$(pwd)/test/config/without-accounts/":/tmp/docker-mailserver/ \
`docker inspect --format '{{ .Config.Image }}' mail` /bin/sh -c 'grep user3@domain.tld -i /tmp/docker-mailserver/postfix-accounts.cf'
@ -730,6 +798,17 @@
run ./setup.sh -c mail email list
[ "$status" -eq 0 ]
}
@test "checking setup.sh: setup.sh email update" {
initialpass=$(cat ./config/postfix-accounts.cf | grep lorem@impsum.org | awk -F '|' '{print $2}')
run ./setup.sh -c mail email update lorem@impsum.org consectetur
updatepass=$(cat ./config/postfix-accounts.cf | grep lorem@impsum.org | awk -F '|' '{print $2}')
if [ initialpass != changepass ]; then
status="0"
else
status="1"
fi
[ "$status" -eq 0 ]
}
@test "checking setup.sh: setup.sh email del" {
run ./setup.sh -c mail email del lorem@impsum.org
[ "$status" -eq 0 ]
@ -808,6 +887,27 @@
[ "$status" -eq 0 ]
}
#
# RIMAP
#
# dovecot
@test "checking dovecot: ldap rimap connection and authentication works" {
run docker exec mail_with_imap /bin/sh -c "nc -w 1 0.0.0.0 143 < /tmp/docker-mailserver-test/auth/imap-auth.txt"
[ "$status" -eq 0 ]
}
# saslauthd
@test "checking saslauthd: sasl rimap authentication works" {
run docker exec mail_with_imap bash -c "testsaslauthd -u user1@localhost.localdomain -p mypassword"
[ "$status" -eq 0 ]
}
@test "checking saslauthd: rimap smtp authentication" {
run docker exec mail_with_imap /bin/sh -c "nc -w 5 0.0.0.0 25 < /tmp/docker-mailserver-test/auth/smtp-auth-login.txt | grep 'Authentication successful'"
[ "$status" -eq 0 ]
}
#
# Postfix VIRTUAL_TRANSPORT
#
@ -820,4 +920,4 @@
run docker exec mail_lmtp_ip /bin/sh -c "grep 'postfix/lmtp' /var/log/mail/mail.log | grep 'status=sent' | grep ' Saved)' | wc -l"
[ "$status" -eq 0 ]
[ "$output" -eq 6 ]
}