added LDAP to dovecot and postfix (TODO: regression test & improve DOC)

This commit is contained in:
Dimitri Kopriwa 2016-08-06 11:28:44 +07:00
parent 4872d0e777
commit 2d06c0c430
8 changed files with 340 additions and 30 deletions

183
README.md
View File

@ -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 = <Password>
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

View File

@ -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

View File

@ -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/postfix/ssl/cacert.pem
auth_debug_passwords= no
userdb {
driver = ldap
args = /etc/dovecot/conf.d/auth-ldap.conf.ext
}
passdb {
driver = ldap
args = /etc/dovecot/conf.d/auth-ldap.conf.ext
}
service imap-login {
inet_listener imap {
port = 0
}
inet_listener imaps {
port = 993
ssl = yes
}
}
service pop3-login {
inet_listener pop3 {
port = 0
}
inet_listener pop3s {
port = 995
ssl = yes
}
}

12
config/ldap-accounts.cf Normal file
View File

@ -0,0 +1,12 @@
server_host = ldap://virtual.domain.com
server_port = 389
search_base = dc=mail,dc=domain,dc=com
query_filter = (&(objectClass=CourierMailAccount)(mail=%s))
result_attribute = mailbox
bind = yes
bind_dn = cn=readonly,dc=domain,dc=com
bind_pw = 123456789
version = 3
tls_ca_cert_file = /etc/postfix/ssl/cacert.pem
tls_cert = /etc/postfix/ssl/mail.domain.com-full.pem
tls_key = /etc/postfix/ssl/mail.domain.com-key.pem

13
config/ldap-aliases.cf Normal file
View File

@ -0,0 +1,13 @@
server_host = ldap://virtual.domain.com
server_port = 389
search_base = dc=mail,dc=domain,dc=com
query_filter = (&(objectClass=CourierMailAlias) (mail=%s))
result_attribute = maildrop
bind = yes
bind_dn = cn=readonly,dc=domain,dc=com
bind_pw = 123456789
version = 3
tls_ca_cert_file = /etc/postfix/ssl/cacert.pem
tls_cert = /etc/postfix/ssl/mail.domain.com-full.pem
tls_key = /etc/postfix/ssl/mail.domain.com-key.pem

12
config/ldap-domains.cf Normal file
View File

@ -0,0 +1,12 @@
server_host = ldap://virtual.domain.com
server_port = 389
search_base = dc=mail,dc=domain,dc=com
query_filter = (&(description=virtualDomain)(dc=%s))
result_attribute = dc
bind = yes
bind_dn = cn=readonly,dc=domain,dc=com
bind_pw = 12345789
version = 3
tls_ca_cert_file = /etc/postfix/ssl/cacert.pem
tls_cert = /etc/postfix/ssl/mail.domain.com-full.pem
tls_key = /etc/postfix/ssl/mail.domain.com-key.pem

17
config/ldap/ldap.conf Normal file
View File

@ -0,0 +1,17 @@
#
# LDAP Defaults
#
# See ldap.conf(5) for details
# This file should be world readable but not world writable.
BASE dc=mail,dc=domain,dc=com
URI ldap://virtual.domain.com
#SIZELIMIT 12
#TIMELIMIT 15
#DEREF never
# TLS certificates (needed for GnuTLS)
TLS_CACERT /etc/postfix/ssl/cacert.pem
TLS_REQCERT demand

View File

@ -8,7 +8,7 @@ die () {
#
# Users
#
if [ -f /tmp/docker-mailserver/postfix-accounts.cf ]; then
if [ ! "$ENABLE_LDAP" = "true" ]; then
echo "Checking file line endings"
sed -i 's/\r//g' /tmp/docker-mailserver/postfix-accounts.cf
echo "Regenerating postfix 'vmailbox' and 'virtual' for given users"
@ -16,18 +16,6 @@ if [ -f /tmp/docker-mailserver/postfix-accounts.cf ]; then
# Checking that /tmp/docker-mailserver/postfix-accounts.cf ends with a newline
sed -i -e '$a\' /tmp/docker-mailserver/postfix-accounts.cf
# 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
# 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