diff --git a/Dockerfile b/Dockerfile index 4c893e81..e86fb8f2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,7 +49,9 @@ ADD postfix/main.cf /etc/postfix/main.cf ADD postfix/master.cf /etc/postfix/master.cf ADD postfix/sasl/smtpd.conf /etc/postfix/sasl/smtpd.conf ADD bin/generate-ssl-certificate /usr/local/bin/generate-ssl-certificate +ADD bin/generate-user-databases /usr/local/bin/generate-user-databases RUN chmod +x /usr/local/bin/generate-ssl-certificate +RUN chmod +x /usr/local/bin/generate-user-databases # Get LetsEncrypt signed certificate RUN curl https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem > /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem diff --git a/Makefile b/Makefile index 9311428d..32684463 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ build: run: # Copy test files - cp test/accounts.cf postfix/ + cp -a test/accounts-db/ postfix/ cp test/main.cf postfix/ cp test/virtual postfix/ # Run containers @@ -62,6 +62,6 @@ tests: clean: # Get default files back - git checkout postfix/accounts.cf postfix/main.cf postfix/virtual + git checkout postfix/accounts-db postfix/main.cf postfix/virtual # Remove running test containers docker rm -f mail mail_pop3 mail_smtponly mail_fail2ban diff --git a/README.md b/README.md index acb30ea7..9ddd7680 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Before you open an issue, please have a look this `README`, the [FAQ](https://gi ### Users -Users are managed in `postfix/accounts.cf`. +Users are managed in `postfix/accounts.cf` with the helper script `generate-user-databases`. Just add the full email address and its password separated by a pipe. Example: @@ -60,6 +60,14 @@ Example: user1@domain.tld|mypassword user2@otherdomain.tld|myotherpassword +Then the user databases for courier and cyrus sasl with encrypted passwords must be generated with the following: + + docker run -ti --rm -v "$(pwd)"/postfix:/tmp/postfix -h mail.domain.com -t tvial/docker-mailserver generate-user-databases + +The needed DBs will then be found inside `postfix/accounts-db/` folder. + +For **security reason** clear text passwords are no longer allowed on running instances of the image. For that reason the file `postfix/accounts.cf` MUST be removed before starting up the container (it will not start up if that file is still there). + ### Aliases Please first read [Postfix documentation on virtual aliases](http://www.postfix.org/VIRTUAL_README.html#virtual_alias). diff --git a/bin/generate-user-databases b/bin/generate-user-databases new file mode 100644 index 00000000..01e4cf9e --- /dev/null +++ b/bin/generate-user-databases @@ -0,0 +1,24 @@ +#!/bin/bash + +# Generate the courier and sasl databases +if [ -f /tmp/postfix/accounts.cf ]; then + # Checking that /tmp/postfix/accounts.cf ends with a newline + sed -i -e '$a\' /tmp/postfix/accounts.cf + + # Creating users + while IFS=$'|' read login pass + do + # Setting variables for better readability + user=$(echo ${login} | cut -d @ -f1) + domain=$(echo ${login} | cut -d @ -f2) + # Let's go! + echo "user '${user}' for domain '${domain}' with password '********'" + /usr/sbin/userdb ${login} set uid=5000 gid=5000 home=/var/mail/${domain}/${user} mail=/var/mail/${domain}/${user} + echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw + echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} + done < /tmp/postfix/accounts.cf + mkdir -p /tmp/postfix/accounts-db + cp /etc/courier/userdb /tmp/postfix/accounts-db/userdb + cp /etc/sasldb2 /tmp/postfix/accounts-db/sasldb2 + echo "Courier and Sasl databases populated with user accounts" +fi diff --git a/postfix/accounts-db/sasldb2 b/postfix/accounts-db/sasldb2 new file mode 100644 index 00000000..e664c9db Binary files /dev/null and b/postfix/accounts-db/sasldb2 differ diff --git a/postfix/accounts-db/userdb b/postfix/accounts-db/userdb new file mode 100644 index 00000000..a52a38c7 --- /dev/null +++ b/postfix/accounts-db/userdb @@ -0,0 +1,2 @@ +user1@localhost.localdomain mail=/var/mail/localhost.localdomain/user1|home=/var/mail/localhost.localdomain/user1|gid=5000|systempw=$1$iq3AGWp2$sCcf9iFXH.cfpbkxhjnxv1|uid=5000 +user2@otherdomain.tld home=/var/mail/otherdomain.tld/user2|systempw=$1$NEKWjXTp$H1KY2dUwE5EZ8Nitiotdu0|gid=5000|uid=5000|mail=/var/mail/otherdomain.tld/user2 diff --git a/postfix/accounts.cf b/postfix/accounts.cf deleted file mode 100644 index ecb0f063..00000000 --- a/postfix/accounts.cf +++ /dev/null @@ -1 +0,0 @@ -user@domain.tld|mypassword diff --git a/test/accounts.cf b/postfix/disab.accounts.cf similarity index 100% rename from test/accounts.cf rename to postfix/disab.accounts.cf diff --git a/start-mailserver.sh b/start-mailserver.sh index 61be65d3..787c8c72 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -5,40 +5,58 @@ die () { exit 1 } +mkpaths () { + test ! -z "$1" && domain=$1 || die "mkpaths: no domain provided... Exiting" + test ! -z "$2" && user=$2 || die "mkpaths: no user provided... Exiting" + + mkdir -p /var/mail/${domain} + if [ ! -d "/var/mail/${domain}/${user}" ]; then + maildirmake "/var/mail/${domain}/${user}" + maildirmake "/var/mail/${domain}/${user}/.Sent" + maildirmake "/var/mail/${domain}/${user}/.Trash" + maildirmake "/var/mail/${domain}/${user}/.Drafts" + echo -e "INBOX\nINBOX.Sent\nINBOX.Trash\nInbox.Drafts" >> "/var/mail/${domain}/${user}/courierimapsubscribed" + touch "/var/mail/${domain}/${user}/.Sent/maildirfolder" + fi + echo ${domain} >> /tmp/vhost.tmp +} + +# must exit with explicit message! if [ -f /tmp/postfix/accounts.cf ]; then + echo "=======================================================================================" + echo "SECURITY WARNING ==> ABORTED startup !" + echo "The image no longer support running with clear text passwords in accounts.cf!" + echo "Accounts must be setup with their utility (generate-user-databases) before starting up" + echo "that image AND accounts.cf must be removed when user DBs are setup." + echo "If your DBs are already setup please remove the file accounts.cf and restart." + echo "For more infos please read the README.md" + echo "=======================================================================================" + exit 1 +fi + +if [ -f /tmp/postfix/accounts-db/userdb -a -f /tmp/postfix/accounts-db/sasldb2 ]; then + CDB="/etc/courier/userdb" + SASLDB="/etc/sasldb2" + # User databases have been already prepared + echo "Found user databases already setup" + cp /tmp/postfix/accounts-db/userdb ${CDB} + chown root:root ${CDB} + chmod 600 ${CDB} + cp /tmp/postfix/accounts-db/sasldb2 ${SASLDB} + chown postfix:sasl ${SASLDB} + chmod 660 ${SASLDB} echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" echo "# WARNING: this file is auto-generated. Modify accounts.cf in postfix directory on host" > /etc/postfix/vmailbox - - # Checking that /tmp/postfix/accounts.cf ends with a newline - sed -i -e '$a\' /tmp/postfix/accounts.cf - - # Creating users - while IFS=$'|' read login pass - do - # Setting variables for better readability - user=$(echo ${login} | cut -d @ -f1) - domain=$(echo ${login} | cut -d @ -f2) - # Let's go! - echo "user '${user}' for domain '${domain}' with password '********'" - echo "${login} ${domain}/${user}/" >> /etc/postfix/vmailbox - /usr/sbin/userdb ${login} set uid=5000 gid=5000 home=/var/mail/${domain}/${user} mail=/var/mail/${domain}/${user} - echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw - echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} - mkdir -p /var/mail/${domain} - if [ ! -d "/var/mail/${domain}/${user}" ]; then - maildirmake "/var/mail/${domain}/${user}" - maildirmake "/var/mail/${domain}/${user}/.Sent" - maildirmake "/var/mail/${domain}/${user}/.Trash" - maildirmake "/var/mail/${domain}/${user}/.Drafts" - echo -e "INBOX\nINBOX.Sent\nINBOX.Trash\nInbox.Drafts" >> "/var/mail/${domain}/${user}/courierimapsubscribed" - touch "/var/mail/${domain}/${user}/.Sent/maildirfolder" - - fi - echo ${domain} >> /tmp/vhost.tmp - done < /tmp/postfix/accounts.cf + # Create the expected maildir paths + awk '{u=substr($1,1,index($1,"@")-1); d=substr($1,index($1,"@")+1,length($1)); print u" "d}' ${CDB} | \ + while read user domain; do + mkpaths ${domain} ${user} + echo "${user}@${domain} ${domain}/${user}/" >> /etc/postfix/vmailbox + done makeuserdb -else - echo "==> Warning: '/tmp/postfix/accounts.cf' is not provided. No mail account created." +else + echo "==> Accounts: '/tmp/postfix/userdb' and '/tmp/postfix/sasldb2' missing.' " + echo "==> Warning: User databases have not been provided. No mail account created." fi if [ -f /tmp/postfix/virtual ]; then @@ -128,7 +146,7 @@ case $DMS_SSL in && [ -e "/etc/letsencrypt/live/$(hostname)/privkey.pem" ]; then echo "Adding $(hostname) SSL certificate" # create combined.pem from (cert|chain|privkey).pem with eol after each .pem - sed -e '$a\' -s "/etc/letsencrypt/live/$(hostname)/{cert,chain,privkey}.pem" > "/etc/letsencrypt/live/$(hostname)/combined.pem" + sed -e '$a\' -s /etc/letsencrypt/live/$(hostname)/{cert,chain,privkey}.pem > /etc/letsencrypt/live/$(hostname)/combined.pem # 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 diff --git a/test/accounts-db/sasldb2 b/test/accounts-db/sasldb2 new file mode 100644 index 00000000..e664c9db Binary files /dev/null and b/test/accounts-db/sasldb2 differ diff --git a/test/accounts-db/userdb b/test/accounts-db/userdb new file mode 100644 index 00000000..a52a38c7 --- /dev/null +++ b/test/accounts-db/userdb @@ -0,0 +1,2 @@ +user1@localhost.localdomain mail=/var/mail/localhost.localdomain/user1|home=/var/mail/localhost.localdomain/user1|gid=5000|systempw=$1$iq3AGWp2$sCcf9iFXH.cfpbkxhjnxv1|uid=5000 +user2@otherdomain.tld home=/var/mail/otherdomain.tld/user2|systempw=$1$NEKWjXTp$H1KY2dUwE5EZ8Nitiotdu0|gid=5000|uid=5000|mail=/var/mail/otherdomain.tld/user2 diff --git a/test/disab.accounts.cf b/test/disab.accounts.cf new file mode 100644 index 00000000..8f209cc6 --- /dev/null +++ b/test/disab.accounts.cf @@ -0,0 +1,2 @@ +user1@localhost.localdomain|mypassword +user2@otherdomain.tld|mypassword diff --git a/test/tests.bats b/test/tests.bats index 709fcae5..47ceca9c 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -195,7 +195,15 @@ # accounts # +@test "checking accounts.cf: if present shouldn't start the container" { + cp `pwd`/postfix/disab.accounts.cf `pwd`/postfix/accounts.cf + run docker run --rm --name test_on_accounts -v "$(pwd)/postfix":/tmp/postfix `docker inspect --format '{{ .Config.Image }}' mail` + [ "$status" -eq 1 ] + [ "${lines[1]}" = "SECURITY WARNING ==> ABORTED startup !" ] +} + @test "checking accounts: user accounts" { + rm -f `pwd`/postfix/accounts.cf run docker exec mail sasldblistusers2 [ "$status" -eq 0 ] [ "${lines[0]}" = "user1@localhost.localdomain: userPassword" ]