From 44622e629270535e213a19c7aa8ed2923c1d0eee Mon Sep 17 00:00:00 2001 From: Moritz Marquardt Date: Sat, 22 May 2021 00:17:29 +0200 Subject: [PATCH] docs: Improve LDAP documentation (#1921) * docs(ldap): Make DOVECOT_PASS_FILTER clearer and add a small DOVECOT_AUTH_BIND section * docs(ldap): Remove superfluous environment variables as of #1989 * docs(ldap): Document defaults for DOVECOT_*_ATTRS/FILTER * docs(ldap): Add documentation for LDAP with TLS and StartTLS Co-authored-by: Frederic Werner <20406381+wernerfred@users.noreply.github.com> Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com> --- docs/content/config/advanced/auth-ldap.md | 216 ++++++++++++++++++---- 1 file changed, 179 insertions(+), 37 deletions(-) diff --git a/docs/content/config/advanced/auth-ldap.md b/docs/content/config/advanced/auth-ldap.md index 81481ac8..0066c4bb 100644 --- a/docs/content/config/advanced/auth-ldap.md +++ b/docs/content/config/advanced/auth-ldap.md @@ -6,37 +6,195 @@ title: 'Advanced | LDAP Authentication' Getting started with ldap and this mailserver we need to take 3 parts in account: -- `postfix` -- `dovecot` -- `saslauthd` (this can also be handled by dovecot) +- `postfix` for incoming & outgoing email +- `dovecot` for accessing mailboxes +- `saslauthd` for SMTP authentication (this can also be delegated to dovecot) ## Variables to Control Provisioning by the Container Have a look at [the ENV page][docs-environment] for information on the default values. -!!! example "postfix" +### `LDAP_QUERY_FILTER_*` +Those variables contain the LDAP lookup filters for postfix, using `%s` as the placeholder for the domain or email address in question. This means that... - - `LDAP_QUERY_FILTER_USER` - - `LDAP_QUERY_FILTER_GROUP` - - `LDAP_QUERY_FILTER_ALIAS` - - `LDAP_QUERY_FILTER_DOMAIN` - - `LDAP_QUERY_FILTER_SENDERS` +- ...for incoming email, the domain must return an entry for the `DOMAIN` filter (see [`virtual_alias_domains`](http://www.postfix.org/postconf.5.html#virtual_alias_domains)). +- ...for incoming email, the inboxes which receive the email are chosen by the `USER`, `ALIAS` and `GROUP` filters. + - The `USER` filter specifies personal mailboxes, for which only one should exist per address, for example `(mail=%s)` (also see [`virtual_mailbox_maps`](http://www.postfix.org/postconf.5.html#virtual_mailbox_maps)) + - The `ALIAS` filter specifies aliases for mailboxes, using [`virtual_alias_maps`](http://www.postfix.org/postconf.5.html#virtual_alias_maps), for example `(mailAlias=%s)` + - The `GROUP` filter specifies the personal mailboxes in a group (for emails that multiple people shall receive), using [`virtual_alias_maps`](http://www.postfix.org/postconf.5.html#virtual_alias_maps), for example `(mailGroupMember=%s)` + - Technically, there is no difference between `ALIAS` and `GROUP`, but ideally you should use `ALIAS` for personal aliases for a singular person (like `ceo@example.org`) and `GROUP` for multiple people (like `hr@example.org`). +- ...for outgoing email, the sender address is put through the `SENDERS` filter, and only if the authenticated user is one of the returned entries, the email can be sent. + - This only applies if `SPOOF_PROTECTION=1`. + - If the `SENDERS` filter is missing, the `USER`, `ALIAS` and `GROUP` filters will be used in in a disjunction (OR). + - To for example allow users from the `admin` group to spoof any sender email address, and to force everyone else to only use their personal mailbox address for outgoing email, you can use something like this: `(|(memberOf=cn=admin,*)(mail=%s))` -!!! example "saslauthd" +???+ example - - `SASLAUTHD_LDAP_FILTER` - -!!! example "dovecot" - - - `DOVECOT_USER_FILTER` - - `DOVECOT_PASS_FILTER` - -## LDAP Setup - Kopano / Zarafa - -???+ example "Example Code" + A really simple `LDAP_QUERY_FILTER` configuration, using only the _user filter_ and allowing only `admin@*` to spoof any sender addresses. + + ```yaml + - ENABLE_LDAP=1 + - LDAP_SERVER_HOST=ldap.example.org + - LDAP_SEARCH_BASE=dc=example,dc=org" + - LDAP_BIND_DN=cn=admin,dc=example,dc=org + - LDAP_BIND_PW=mypassword + - SPOOF_PROTECTION=1 + + - LDAP_QUERY_FILTER_DOMAIN=(mail=*@%s) + - LDAP_QUERY_FILTER_USER=(mail=%s) + - LDAP_QUERY_FILTER_ALIAS=(|) # doesn't match anything + - LDAP_QUERY_FILTER_GROUP=(|) # doesn't match anything + - LDAP_QUERY_FILTER_SENDERS=(|(mail=%s)(mail=admin@*)) + ``` + +### `DOVECOT_*_FILTER` & `DOVECOT_*_ATTRS` +These variables specify the LDAP filters that dovecot uses to determine if a user can log in to their IMAP account, and which mailbox is responsible to receive email for a specific postfix user. + +This is split into the following two lookups, both using `%u` as the placeholder for the full login name ([see dovecot documentation for a full list of placeholders](https://doc.dovecot.org/configuration_manual/config_file/config_variables/)). Usually you only need to set `DOVECOT_USER_FILTER`, in which case it will be used for both filters. + +- `DOVECOT_USER_FILTER` is used to get the account details (uid, gid, home directory, quota, ...) of a user. +- `DOVECOT_PASS_FILTER` is used to get the password information of the user, and is in pretty much all cases identical to `DOVECOT_USER_FILTER` (which is the default behaviour if left away). + +If your directory doesn't have the [postfix-book schema](https://github.com/variablenix/ldap-mail-schema/blob/master/postfix-book.schema) installed, then you must change the internal attribute handling for dovecot. For this you have to change the `pass_attr` and the `user_attr` mapping, as shown in the example below: + +```yaml +- DOVECOT_PASS_ATTRS==user,=password +- DOVECOT_USER_ATTRS==home,=mail,=uid,=gid +``` + +!!! note + + For `DOVECOT_*_ATTRS`, you can replace `ldapAttr=dovecotAttr` with `=dovecotAttr=%{ldap:ldapAttr}` for more flexibility, like for example `=home=/var/mail/%{ldap:uid}` or just `=uid=5000`. + + A list of dovecot attributes can be found [in the dovecot documentation](https://doc.dovecot.org/configuration_manual/authentication/user_databases_userdb/#authentication-user-database). + +???+ example "Defaults" + + ```yaml + - DOVECOT_USER_ATTRS=mailHomeDirectory=home,mailUidNumber=uid,mailGidNumber=gid,mailStorageDirectory=mail + - DOVECOT_PASS_ATTRS=uniqueIdentifier=user,userPassword=password + - DOVECOT_USER_FILTER=(&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n)) + ``` + +???+ example + + Setup for a directory that has the [qmail-schema](https://github.com/amery/qmail/blob/master/qmail.schema) installed and uses `uid`: + + ```yaml + - DOVECOT_PASS_ATTRS=uid=user,userPassword=password + - DOVECOT_USER_ATTRS=homeDirectory=home,qmailUID=uid,qmailGID=gid,mailMessageStore=mail + - DOVECOT_USER_FILTER=(&(objectClass=qmailUser)(uid=%u)(accountStatus=active)) + ``` + +The LDAP server configuration for dovecot will be taken mostly from postfix, other options can be found in [the environment section in the docs][docs-environment]. + +### `DOVECOT_AUTH_BIND` +Set this to `yes` to enable authentication binds ([more details in the dovecot documentation](https://wiki.dovecot.org/AuthDatabase/LDAP/AuthBinds)). Currently, only DN lookup is supported without further changes to the configuration files, so this is only useful when you want to bind as a readonly user without the permission to read passwords. + +### `SASLAUTHD_LDAP_FILTER` +This filter is used for `saslauthd`, which is called by postfix when someone is authenticating through SMTP (assuming that `SASLAUTHD_MECHANISMS=ldap` is being used). Note that you'll need to set up the LDAP server for saslauthd seperately from postfix. + +The filter variables are explained in detail [in the `LDAP_SASLAUTHD` file](https://github.com/winlibs/cyrus-sasl/blob/master/saslauthd/LDAP_SASLAUTHD#L121), but unfortunately, this method doesn't really support domains right now - that means that `%U` is the only token that makes sense in this variable. + +!!! note "When to use this and how to avoid it" + + Using a separate filter for SMTP authentication allows you to for example allow `noreply@example.org` to send email, but not log in to IMAP or receive email: `(&(mail=%U@example.org)(|(memberOf=cn=email,*)(mail=noreply@example.org)))` + + If you don't want to use a separate filter for SMTP authentication, you can set `SASLAUTHD_MECHANISMS=rimap` and `SASLAUTHD_MECH_OPTIONS=127.0.0.1` to authenticate against dovecot instead - this means that the `DOVECOT_USER_FILTER` and `DOVECOT_PASS_FILTER` will be used for SMTP authentication as well. + +???+ example "Configure LDAP with `saslauthd`" + + ```yaml + - ENABLE_SASLAUTHD=1 + - SASLAUTHD_MECHANISMS=ldap + - SASLAUTHD_LDAP_FILTER=(mail=%U@example.org) + ``` + +## Secure Connection with LDAPS or StartTLS +To enable LDAPS, all you need to do is to add the protocol to `LDAP_SERVER_HOST`, for example `ldaps://example.org:636`. + +To enable LDAP over StartTLS (on port 389), you need to set the following environment variables instead (the **protocol must not be `ldaps://`** in this case!): + +```yaml +- LDAP_START_TLS=yes +- DOVECOT_TLS=yes +- SASLAUTHD_LDAP_START_TLS=yes +``` + +## LDAP Setup Examples + +???+ example "Basic Setup" + + ```yaml + version: '2' + services: + mail: + image: mailserver/docker-mailserver:latest + hostname: mail + domainname: example.org + container_name: mail + + ports: + - "25:25" + - "143:143" + - "587:587" + - "993:993" + + volumes: + - maildata:/var/mail + - mailstate:/var/mail-state + - ./config/:/tmp/docker-mailserver/ + + environment: + - ENABLE_SPAMASSASSIN=1 + - ENABLE_CLAMAV=1 + - ENABLE_FAIL2BAN=1 + - ENABLE_POSTGREY=1 + + # >>> Postfix LDAP Integration + - ENABLE_LDAP=1 + - LDAP_SERVER_HOST=ldap.example.org + - LDAP_BIND_DN=cn=admin,ou=users,dc=example,dc=org + - LDAP_BIND_PW=mypassword + - LDAP_SEARCH_BASE=dc=example,dc=org + - LDAP_QUERY_FILTER_DOMAIN=(|(mail=*@%s)(mailAlias=*@%s)(mailGroupMember=*@%s)) + - LDAP_QUERY_FILTER_USER=(&(objectClass=inetOrgPerson)(mail=%s)) + - LDAP_QUERY_FILTER_ALIAS=(&(objectClass=inetOrgPerson)(mailAlias=%s)) + - LDAP_QUERY_FILTER_GROUP=(&(objectClass=inetOrgPerson)(mailGroupMember=%s)) + - LDAP_QUERY_FILTER_SENDERS=(&(objectClass=inetOrgPerson)(|(mail=%s)(mailAlias=%s)(mailGroupMember=%s))) + - SPOOF_PROTECTION=1 + # <<< Postfix LDAP Integration + + # >>> Dovecot LDAP Integration + - DOVECOT_USER_FILTER=(&(objectClass=inetOrgPerson)(mail=%u)) + - DOVECOT_PASS_ATTRS=uid=user,userPassword=password + - DOVECOT_USER_ATTRS==home=/var/mail/%{ldap:uid},=mail=maildir:~/Maildir,uidNumber=uid,gidNumber=gid + # <<< Dovecot LDAP Integration + + # >>> SASL LDAP Authentication + - ENABLE_SASLAUTHD=1 + - SASLAUTHD_MECHANISMS=ldap + - SASLAUTHD_LDAP_FILTER=(&(mail=%U@example.org)(objectClass=inetOrgPerson)) + # <<< SASL LDAP Authentication + + - ONE_DIR=1 + - DMS_DEBUG=0 + - SSL_TYPE=letsencrypt + - PERMIT_DOCKER=host + + cap_add: + - NET_ADMIN + + volumes: + maildata: + driver: local + mailstate: + driver: local + ``` + +??? example "Kopano / Zarafa" ```yaml - --- version: '2' services: @@ -109,20 +267,4 @@ Have a look at [the ENV page][docs-environment] for information on the default v driver: local ``` -If your directory has not the postfix-book schema installed, then you must change the internal attribute handling for dovecot. For this you have to change the `pass_attr` and the `user_attr` mapping, as shown in the example below: - -```yaml -- DOVECOT_PASS_ATTR==user,=password -- DOVECOT_USER_ATTR==home,=mail,=uid, =gid -``` - -The following example illustrates this for a directory that has the qmail-schema installed and that uses `uid`: - -```yaml -- DOVECOT_PASS_ATTRS=uid=user,userPassword=password -- DOVECOT_USER_ATTRS=homeDirectory=home,qmailUID=uid,qmailGID=gid,mailMessageStore=mail -- DOVECOT_PASS_FILTER=(&(objectClass=qmailUser)(uid=%u)(accountStatus=active)) -- DOVECOT_USER_FILTER=(&(objectClass=qmailUser)(uid=%u)(accountStatus=active)) -``` - [docs-environment]: ../environment.md