diff --git a/README.md b/README.md index 054133bf..b17b0573 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,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/opedkim/keys/domain.tld/mail.txt` in your `domain.tld.hosts` zone. +Note: if you are using ldap, you will have to generate the key firsts with the non ldap mode then move the generated `opendkim` folders in `config` + #### Start the container docker-compose up -d mail @@ -105,6 +107,187 @@ If you enable Fail2Ban, don't forget to add the following lines to your `docker- Otherwise, `iptables` won't be able to ban IPs. +##### ENABLE_LDAP + + - **empty** => LDAP disabled + - "true" => Enables LDAP + +If you enable LDAP, don't forget to add the following lines to your `docker-compose.yml`: + + volumes: + - ./config/conf.d/auth-ldap.conf.ext:/tmp/docker-mailserver/conf.d/auth-ldap.conf.ext + - ./config/ldap-accounts.cf:/tmp/docker-mailserver/ldap-accounts.cf + - ./config/ldap-aliases.cf:/tmp/docker-mailserver/ldap-aliases.cf + - ./config/ldap-domains.cf:/tmp/docker-mailserver/ldap-domains.cf + +Read this [article](https://wiki.gandi.net/en/hosting/using-linux/tutorials/debian/mail-server-ldap) more details on how to configure OpenLDAP with postfix + +__Example of configuration :__ + +If you need a OpenLDAP Docker image, this configuration was test with this [image](https://github.com/osixia/docker-openldap) + +06-authldap.ldif is the user schema use for creating the account below + + dn: cn=authldap,cn=schema,cn=config + changetype: add + objectClass: olcSchemaConfig + cn: authldap + olcAttributeTypes: {0}( 1.3.6.1.4.1.10018.1.1.1 NAME 'mailbox' DESC 'The abs + olute path to the mailbox for a mail account in a non-default location' EQU + ALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) + olcAttributeTypes: {1}( 1.3.6.1.4.1.10018.1.1.2 NAME 'quota' DESC 'A string + that represents the quota on a mailbox' EQUALITY caseExactIA5Match SYNTAX 1 + .3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) + olcAttributeTypes: {2}( 1.3.6.1.4.1.10018.1.1.3 NAME 'clearPassword' DESC 'A + separate text that stores the mail account password in clear text' EQUALIT + Y octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} ) + olcAttributeTypes: {3}( 1.3.6.1.4.1.10018.1.1.4 NAME 'maildrop' DESC 'RFC822 + Mailbox - mail alias' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5Subs + tringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} ) + olcAttributeTypes: {4}( 1.3.6.1.4.1.10018.1.1.5 NAME 'mailsource' DESC 'Mess + age source' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + olcAttributeTypes: {5}( 1.3.6.1.4.1.10018.1.1.6 NAME 'virtualdomain' DESC 'A + mail domain that is mapped to a single mail account' EQUALITY caseIgnoreIA + 5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121. + 1.26 ) + olcAttributeTypes: {6}( 1.3.6.1.4.1.10018.1.1.7 NAME 'virtualdomainuser' DES + C 'Mailbox that receives mail for a mail domain' EQUALITY caseIgnoreIA5Matc + h SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + ) + olcAttributeTypes: {7}( 1.3.6.1.4.1.10018.1.1.8 NAME 'defaultdelivery' DESC + 'Default mail delivery instructions' EQUALITY caseExactIA5Match SYNTAX 1.3. + 6.1.4.1.1466.115.121.1.26 ) + olcAttributeTypes: {8}( 1.3.6.1.4.1.10018.1.1.9 NAME 'disableimap' DESC 'Set + this attribute to 1 to disable IMAP access' EQUALITY caseExactIA5Match SYN + TAX 1.3.6.1.4.1.1466.115.121.1.26 ) + olcAttributeTypes: {9}( 1.3.6.1.4.1.10018.1.1.10 NAME 'disablepop3' DESC 'Se + t this attribute to 1 to disable POP3 access' EQUALITY caseExactIA5Match SY + NTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + olcAttributeTypes: {10}( 1.3.6.1.4.1.10018.1.1.11 NAME 'disablewebmail' DESC + 'Set this attribute to 1 to disable IMAP access' EQUALITY caseExactIA5Matc + h SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + olcAttributeTypes: {11}( 1.3.6.1.4.1.10018.1.1.12 NAME 'sharedgroup' DESC 'V + irtual shared group' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115 + .121.1.26 ) + olcAttributeTypes: {12}( 1.3.6.1.4.1.10018.1.1.13 NAME 'disableshared' DESC + 'Set this attribute to 1 to disable shared mailbox usage' EQUALITY caseExac + tIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + olcAttributeTypes: {13}( 1.3.6.1.4.1.10018.1.1.14 NAME 'mailhost' DESC 'Host + to which incoming POP/IMAP connections should be proxied' EQUALITY caseIgn + oreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} ) + olcObjectClasses: {0}( 1.3.6.1.4.1.10018.1.2.1 NAME 'CourierMailAccount' DES + C 'Mail account object as used by the Courier mail server' SUP top AUXILIAR + Y MUST ( mail $ homeDirectory ) MAY ( uidNumber $ gidNumber $ mailbox $ uid + $ cn $ gecos $ description $ loginShell $ quota $ userPassword $ clearPass + word $ defaultdelivery $ disableimap $ disablepop3 $ disablewebmail $ share + dgroup $ disableshared $ mailhost ) ) + olcObjectClasses: {1}( 1.3.6.1.4.1.10018.1.2.2 NAME 'CourierMailAlias' DESC + 'Mail aliasing/forwarding entry' SUP top AUXILIARY MUST ( mail $ maildrop ) + MAY ( mailsource $ description ) ) + olcObjectClasses: {2}( 1.3.6.1.4.1.10018.1.2.3 NAME 'CourierDomainAlias' DES + C 'Domain mail aliasing/forwarding entry' SUP top AUXILIARY MUST ( virtuald + omain $ virtualdomainuser ) MAY ( mailsource $ description ) ) + +10-mail-tree.ldif + + # -------------------------------------------------------------------- + # Create the dc=mail under dc=domain,dc=com + # -------------------------------------------------------------------- + dn: dc=mail,dc=domain,dc=com + changetype: add + dc: mail + o: mail + objectClass: top + objectClass: dcObject + objectClass: organization + + dn: dc=domain.com,dc=mail,dc=domain,dc=com + changetype: add + o: domain.com + dc: domain.com + description: virtualDomain + objectClass: top + objectClass: dcObject + objectClass: organization + + dn: dc=mailAccount,dc=domain.com,dc=mail,dc=domain,dc=com + changetype: add + dc: mailAccount + o: mailAccount + objectClass: top + objectClass: dcObject + objectClass: organization + + dn: dc=mailAlias,dc=domain.com,dc=mail,dc=domain,dc=com + changetype: add + dc: mailAlias + o: mailAlias + objectClass: top + objectClass: dcObject + objectClass: organization + +50-user-email.ldif entry used on my OpenLDAP server + +_Note : The `userPassword` present here is the SSHA representation of "enter"_ + + # -------------------------------------------------------------------- + # Create mail accounts + # -------------------------------------------------------------------- + dn: mail=somebody@domain.com,dc=mailAccount,dc=domain.com,dc=mail,dc=domain,dc=com + changetype: add + sn: Wayne + givenName: Bruce + displayName: Bruce Wayne + cn: somebody@domain.com + mail: somebody@domain.com + mailbox: domaine.com/bruce.wayne/ + homeDirectory: /var/mail + objectClass: top + objectClass: inetOrgPerson + objectClass: CourierMailAccount + userPassword: {SSHA}Ys9NZMHhZ7woTrgK7GUXXQ3NkMEH2gom + + # -------------------------------------------------------------------- + # Create alias accounts + # -------------------------------------------------------------------- + dn: mail=batman@domain.com,dc=mailAlias,dc=domain.com,dc=mail,dc=domain,dc=com + changetype: add + cn: batman@domain.com + mail: batman@domain.com + maildrop: bruce.wayne@domain.com + sn: Wayne + givenName: Bruce + displayName: Bruce Wayne + objectClass: top + objectClass: inetOrgPerson + objectClass: CourierMailAlias + +Create a file `conf.d/auth-ldap.conf.ext`, this will override the current authentication mechanism + + hosts = ldap.domain.com + ldap_version = 3 + auth_bind = yes + dn = cn=admin,dc=domain,dc=com + dnpass = + base = dc=mail,dc=domain,dc=com + user_filter = (&(objectClass=CourierMailAccount)(mail=%u)) + pass_filter = (&(objectClass=CourierMailAccount)(mail=%u)) + user_attrs = uidNumber=5000,gidNumber=5000,homeDirectory=home,mailbox=mail + default_pass_scheme = SSHA + +Create a file `config/conf.d/ldap-accounts.cf` + + server_host = ldap.domain.com # Host of your ldap server + server_port = 389 + search_base = dc=mail,dc=domain,dc=com # Where to search mail account from + query_filter = (&(objectClass=CourierMailAccount)(mail=%s)) # This require to have the CourierMailAccount class (see below) + result_attribute = mailbox + bind = yes + bind_dn = cn=readonly,dc=domain,dc=com + bind_pw = readonlypw + version = 3 + ##### ENABLE_MANAGESIEVE - **empty** => Managesieve service disabled diff --git a/config/conf.d/auth-ldap.conf.ext b/config/conf.d/auth-ldap.conf.ext new file mode 100644 index 00000000..6b3e89d6 --- /dev/null +++ b/config/conf.d/auth-ldap.conf.ext @@ -0,0 +1,13 @@ +# SSL/TLS +uris = ldap://virtual.domain.com +auth_bind = yes +ldap_version = 3 +dn = cn=readonly,dc=domain,dc=com +dnpass = 123456789 +base = dc=mail,dc=domain,dc=com +user_filter = (&(objectClass=CourierMailAccount)(mail=%u)) +pass_filter = (&(objectClass=CourierMailAccount)(mail=%u)) +user_attrs = uidNumber=5000,gidNumber=5000,homeDirectory=home,mailbox=mail=maildir:%$/Maildir:LAYOUT=fs +default_pass_scheme = SSHA +tls = yes +tls_ca_cert_file = /etc/postfix/ssl/cacert.pem diff --git a/config/dovecot.cf b/config/dovecot.cf index f1358884..be658de6 100644 --- a/config/dovecot.cf +++ b/config/dovecot.cf @@ -2,3 +2,43 @@ # For more informations read http://wiki.dovecot.org/BasicConfiguration #mail_max_userip_connections = 50 + +login_greeting = My Server : server ready +mail_uid = 5000 +mail_gid = 5000 +auth_mechanisms = plain login +disable_plaintext_auth = yes + +ssl_ca = /etc/dovecot/userdb - chown dovecot:dovecot /etc/dovecot/userdb - chmod 640 /etc/dovecot/userdb - cp -a /usr/share/dovecot/protocols.d /etc/dovecot/ - # Disable pop3 (it will be eventually enabled later in the script, if requested) - mv /etc/dovecot/protocols.d/pop3d.protocol /etc/dovecot/protocols.d/pop3d.protocol.disab - mv /etc/dovecot/protocols.d/managesieved.protocol /etc/dovecot/protocols.d/managesieved.protocol.disab - sed -i -e 's/#ssl = yes/ssl = yes/g' /etc/dovecot/conf.d/10-master.conf - sed -i -e 's/#port = 993/port = 993/g' /etc/dovecot/conf.d/10-master.conf - sed -i -e 's/#port = 995/port = 995/g' /etc/dovecot/conf.d/10-master.conf - sed -i -e 's/#ssl = yes/ssl = required/g' /etc/dovecot/conf.d/10-ssl.conf # Creating users # 'pass' is encrypted @@ -61,6 +49,19 @@ else echo "==> Warning: 'config/docker-mailserver/postfix-accounts.cf' is not provided. No mail account created." fi +# Configuring Dovecot +echo -n > /etc/dovecot/userdb +chown dovecot:dovecot /etc/dovecot/userdb +chmod 640 /etc/dovecot/userdb +cp -a /usr/share/dovecot/protocols.d /etc/dovecot/ +# Disable pop3 (it will be eventually enabled later in the script, if requested) +mv /etc/dovecot/protocols.d/pop3d.protocol /etc/dovecot/protocols.d/pop3d.protocol.disab +mv /etc/dovecot/protocols.d/managesieved.protocol /etc/dovecot/protocols.d/managesieved.protocol.disab +sed -i -e 's/#ssl = yes/ssl = yes/g' /etc/dovecot/conf.d/10-master.conf +sed -i -e 's/#port = 993/port = 993/g' /etc/dovecot/conf.d/10-master.conf +sed -i -e 's/#port = 995/port = 995/g' /etc/dovecot/conf.d/10-master.conf +sed -i -e 's/#ssl = yes/ssl = required/g' /etc/dovecot/conf.d/10-ssl.conf + # # Aliases # @@ -88,6 +89,8 @@ if [ -f /tmp/docker-mailserver/postfix-regexp.cf ]; then }' /etc/postfix/main.cf fi + + # DKIM # Check if keys are already available if [ -e "/tmp/docker-mailserver/opendkim/KeyTable" ]; then @@ -147,14 +150,16 @@ case $SSL_TYPE in echo "Adding $(hostname) SSL certificate" mkdir -p /etc/postfix/ssl cp "/tmp/docker-mailserver/ssl/$(hostname)-full.pem" /etc/postfix/ssl + cp "/tmp/docker-mailserver/ssl/$(hostname)-key.pem" /etc/postfix/ssl + cp "/tmp/docker-mailserver/ssl/cacert.pem" /etc/postfix/ssl # Postfix configuration sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$(hostname)'-full.pem/g' /etc/postfix/main.cf - sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'-full.pem/g' /etc/postfix/main.cf + sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'-key.pem/g' /etc/postfix/main.cf # Dovecot configuration 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 + 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 'CA signed/custom' certificates" @@ -198,9 +203,30 @@ if [ -f /tmp/vhost.tmp ]; then cat /tmp/vhost.tmp | sort | uniq > /etc/postfix/vhost && rm /tmp/vhost.tmp fi + echo "Postfix configurations" -touch /etc/postfix/vmailbox && postmap /etc/postfix/vmailbox -touch /etc/postfix/virtual && postmap /etc/postfix/virtual +# +# LDAP +# +if [ "$ENABLE_LDAP" = "true" ]; then + echo "Installing LDAP auth mechanism" + cp /tmp/docker-mailserver/ldap-accounts.cf /etc/postfix/ldap-accounts.cf + echo "Loaded /etc/postfix/ldap-accounts.cf" + cp /tmp/docker-mailserver/ldap-aliases.cf /etc/postfix/ldap-aliases.cf + echo "Loaded /etc/postfix/ldap-aliases.cf" + cp /tmp/docker-mailserver/ldap-domains.cf /etc/postfix/ldap-domains.cf + echo "Loaded /etc/postfix/ldap-domains.cf" + cp /tmp/docker-mailserver/conf.d/auth-ldap.conf.ext /etc/dovecot/conf.d/auth-ldap.conf.ext + echo "Uninstalling passwd-file authentication mechanism" + echo "" > /etc/dovecot/conf.d/auth-passwdfile.inc + if [ -e "/tmp/docker-mailserver/ldap/ldap.conf" ]; then + cp /tmp/docker-mailserver/ldap/ldap.conf /etc/ldap/ldap.conf + fi +else + touch /etc/postfix/vmailbox && postmap /etc/postfix/vmailbox + touch /etc/postfix/virtual && postmap /etc/postfix/virtual +fi + # # Override Postfix configuration @@ -264,7 +290,6 @@ SA_KILL=${SA_KILL:="6.31"} && sed -i -r 's/^\$sa_kill_level_deflt (.*);/\$sa_kil test -e /tmp/docker-mailserver/spamassassin-rules.cf && cp /tmp/docker-mailserver/spamassassin-rules.cf /etc/spamassassin/ if [ "$ENABLE_FAIL2BAN" = 1 ]; then - echo "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 @@ -304,7 +329,6 @@ cron # Enable Managesieve service by setting the symlink # to the configuration file Dovecot will actually find if [ "$ENABLE_MANAGESIEVE" = 1 ]; then - echo "Sieve management enabled" mv /etc/dovecot/protocols.d/managesieved.protocol.disab /etc/dovecot/protocols.d/managesieved.protocol fi @@ -326,15 +350,9 @@ if [ -f /tmp/docker-mailserver/dovecot.cf ]; then fi # Start services related to SMTP -if ! [ "$DISABLE_SPAMASSASSIN" = 1 ]; then - /etc/init.d/spamassassin start -fi -if ! [ "$DISABLE_CLAMAV" = 1 ]; then - /etc/init.d/clamav-daemon start -fi -if ! [ "$DISABLE_AMAVIS" = 1 ]; then - /etc/init.d/amavis start -fi +/etc/init.d/spamassassin start +/etc/init.d/clamav-daemon start +/etc/init.d/amavis start /etc/init.d/opendkim start /etc/init.d/opendmarc start /etc/init.d/postfix start @@ -345,8 +363,10 @@ if [ "$ENABLE_FAIL2BAN" = 1 ]; then /etc/init.d/fail2ban start fi -echo "Listing users" -/usr/sbin/dovecot user '*' +if [ ! "$ENABLE_LDAP" = "true" ]; then + echo "Listing users" + /usr/sbin/dovecot user '*' +fi echo "Starting..." tail -f /var/log/mail/mail.log