From 7fa0f72e2b34f8c90b058a395b3f00d41cc82cef Mon Sep 17 00:00:00 2001 From: angus Date: Mon, 11 Apr 2016 16:12:07 +0200 Subject: [PATCH 1/4] Fix bug when combining certs for Letsencrypt. --- start-mailserver.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index 70ce9b81..ea314985 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -125,7 +125,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 From 8e639d2a4619bc7df082453209236371227cd227 Mon Sep 17 00:00:00 2001 From: angus Date: Sat, 16 Apr 2016 15:27:32 +0200 Subject: [PATCH 2/4] Allow to provide pre-configured user databases, with encrypted passwords already setup. The startup logic for user configuration is now as follows: * /tmp/postfix/accounts-db/{userdb,sasldb2} available: DBs copied to the image, users setup completed; * /tmp/postfix/accounts.cf available: users are setup from that file; * otherwise no mail account will be setup. Changes: - Dockerfile: added script to generate-user-databases - generate-user-databases: script can be called to generate DBs from account.cf file and export them to the host - start-mailserver.sh: implemented logic for managing users provided in account.cf files or in user databases --- Dockerfile | 2 + bin/generate-user-databases | 24 ++++++++++ start-mailserver.sh | 93 ++++++++++++++++++++++++------------- 3 files changed, 88 insertions(+), 31 deletions(-) create mode 100644 bin/generate-user-databases 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/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/start-mailserver.sh b/start-mailserver.sh index 92c38ebc..e0d6f0d4 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -5,40 +5,71 @@ die () { exit 1 } -if [ -f /tmp/postfix/accounts.cf ]; then +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 +} + +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 + # should exit with explicit message! + if [ -f /tmp/postfix/accounts.cf ]; then + 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} + # Create the expected maildir paths + mkpaths ${domain} ${user} + done < /tmp/postfix/accounts.cf + makeuserdb + else + echo "==> Accounts: '/tmp/postfix/userdb' and '/tmp/postfix/sasldb2' OR '/tmp/postfix/accounts.cf' " + echo "==> Warning: None of those files are provided. No mail account created." + fi fi if [ -f /tmp/postfix/virtual ]; then From c8eaf655cafc5cf20fd08de09ed5adb759357969 Mon Sep 17 00:00:00 2001 From: angus Date: Sat, 16 Apr 2016 16:56:26 +0200 Subject: [PATCH 3/4] Allow to provide pre-configured user databases, with encrypted passwords already setup. For security reason accounts.cf file must not be provided anymore to the container or it will stop with an error message! User configuration is only allowed via pre-configured user databases. See README.md for instructions. This changes also the way we setup users for CI tests: the right databases have been added and Makefile has been modified accordingly. --- Makefile | 4 +- README.md | 10 +++- postfix/accounts-db/sasldb2 | Bin 0 -> 12288 bytes postfix/accounts-db/userdb | 2 + postfix/accounts.cf | 1 - test/accounts.cf => postfix/disab.accounts.cf | 0 start-mailserver.sh | 43 ++++++------------ test/accounts-db/sasldb2 | Bin 0 -> 12288 bytes test/accounts-db/userdb | 2 + test/disab.accounts.cf | 2 + 10 files changed, 32 insertions(+), 32 deletions(-) create mode 100644 postfix/accounts-db/sasldb2 create mode 100644 postfix/accounts-db/userdb delete mode 100644 postfix/accounts.cf rename test/accounts.cf => postfix/disab.accounts.cf (100%) create mode 100644 test/accounts-db/sasldb2 create mode 100644 test/accounts-db/userdb create mode 100644 test/disab.accounts.cf 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/postfix/accounts-db/sasldb2 b/postfix/accounts-db/sasldb2 new file mode 100644 index 0000000000000000000000000000000000000000..e664c9dbbca3b93bab3b6386f28877b1bc1a0b89 GIT binary patch literal 12288 zcmeI%I|{-;5P;!H3eiGhqrDdh=q>E*?37>v5fWFDh$z43gO7h5uZICJk0=(cJX4QLmu&|NA??D;Hb;-#k0k;?;FO wdH>hFy#H5X%m^TW00IagfB*srAb> /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" @@ -42,34 +55,8 @@ if [ -f /tmp/postfix/accounts-db/userdb -a -f /tmp/postfix/accounts-db/sasldb2 ] done makeuserdb else - # should exit with explicit message! - if [ -f /tmp/postfix/accounts.cf ]; then - 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} - # Create the expected maildir paths - mkpaths ${domain} ${user} - done < /tmp/postfix/accounts.cf - makeuserdb - else - echo "==> Accounts: '/tmp/postfix/userdb' and '/tmp/postfix/sasldb2' OR '/tmp/postfix/accounts.cf' " - echo "==> Warning: None of those files are provided. No mail account created." - fi + 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 diff --git a/test/accounts-db/sasldb2 b/test/accounts-db/sasldb2 new file mode 100644 index 0000000000000000000000000000000000000000..e664c9dbbca3b93bab3b6386f28877b1bc1a0b89 GIT binary patch literal 12288 zcmeI%I|{-;5P;!H3eiGhqrDdh=q>E*?37>v5fWFDh$z43gO7h5uZICJk0=(cJX4QLmu&|NA??D;Hb;-#k0k;?;FO wdH>hFy#H5X%m^TW00IagfB*srAb Date: Tue, 19 Apr 2016 11:50:49 +0200 Subject: [PATCH 4/4] Added test case in tests.bats: container shouldn't start up when an account.cf is present. --- test/tests.bats | 8 ++++++++ 1 file changed, 8 insertions(+) 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" ]