1
1
Fork 0
mirror of https://github.com/docker-mailserver/docker-mailserver synced 2024-05-05 20:16:05 +02:00
docker-mailserver/docs/content/config/advanced/auth-ldap.md
Brennan Kinney a0ee472501
docs(chore): Normalize for consistency (#2206)
"Brief" summary/overview of changes. See the PR discussion or individual commits from the PR for more details.

---

Only applies to the `docs/content/**` content (_and `setup` command_). `target/` and `test/` can be normalized at a later date.

* Normalize to `example.com`

- Domains normalized to `example.com`: `mywebserver.com`, `myserver.tld`, `domain.com`, `domain.tld`, `mydomain.net`, `my-domain.tld`, `my-domain.com`, `example.org`, `whoami.com`.
- Alternative domains normalized to `not-example.com`: `otherdomain.com`, `otherdomain.tld`, `domain2.tld`, `mybackupmx.com`, `whoareyou.org`.
- Email addresses normalized to `admin@example.com` (in `ssl.md`): `foo@bar.com`, `yourcurrentemail@gmail.com`, `email@email.com`, `admin@domain.tld`.
- Email addresses normalized to `external-account@gmail.com`: `bill@gates321boom.com`, `external@gmail.com`, `myemail@gmail.com`, `real-email-address@external-domain.com`.
- **`faq.md`:** A FAQ entry title with `sample.domain.com` changed to `subdomain.example.com`.
- **`mail-fetchmail.md`:** Config examples with FQDNs for `imap`/`pop3` used `example.com` domain for a third-party, changed to `gmail.com` as more familiar third-party/external MTA.

* Normalize config volume path

- Normalizing local config path references to `./docker-data/dms/config/`: `./config/`, `config/`, \``config`\`, `/etc/` (_volume mount src path prefix_).
- Normalize DMS volume paths to `docker-data/dms/mail-{data,state,log}`: `./mail`, `./mail-state` `./data/mail`, `./data/state`, `./data/logs`, `./data/maildata`, `./data/mailstate`, `./data/maillogs`, (_dropped/converted data volumes: `maildata`, `mailstate`_).
- Other docker images also adopt the `docker-data/{service name}/` prefix.

* `ssl.md` - Use `dms/custom-certs` where appropriate.

* Apply normalizations to README and example `docker-compose.yml`

---

Common terms, sometimes interchangeably used or now invalid depending on context: `mail`, `mail container`, `mail server`, `mail-server`, `mailserver`,`docker-mailserver`, `Docker Mailserver`.

Rough transformations applied to most matches (_conditionally, depending on context_):

- 'Docker Mailserver' => '`docker-mailserver`'
- 'mail container' => '`docker-mailserver`' (_optionally retaining ' container'_)
- 'mail server' => 'mail-server' / '`docker-mailserver`'
- 'mail-server' => '`docker-mailserver`'
- 'mailserver' => 'mail-server' / '`docker-mailserver`'

Additionally I checked `docker run` (_plus `exec`, `logs`, etc, sub-commands_) and `docker-compose` commands. Often finding usage of `mail` instead of the expected `mailserver`

Additionally changes `mailserver` hostname in k8s to `mail` to align with other non-k8s examples.

---

* drive-by revisions

Mostly minor revisions or improvements to docs that aren't related to normalization effort.
2021-09-23 11:29:37 +12:00

12 KiB

title
Advanced | LDAP Authentication

Introduction

Getting started with ldap and docker-mailserver we need to take 3 parts in account:

  • 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 for information on the default values.

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

  • ...for incoming email, the domain must return an entry for the DOMAIN filter (see 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)
    • The ALIAS filter specifies aliases for mailboxes, using 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, 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

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). 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 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:

- DOVECOT_PASS_ATTRS=<YOUR_USER_IDENTIFIER_ATTRIBUTE>=user,<YOUR_USER_PASSWORD_ATTRIBUTE>=password
- DOVECOT_USER_ATTRS=<YOUR_USER_HOME_DIRECTORY_ATTRIBUTE>=home,<YOUR_USER_MAILSTORE_ATTRIBUTE>=mail,<YOUR_USER_MAIL_UID_ATTRIBUTE>=uid,<YOUR_USER_MAIL_GID_ATTRIBUTE>=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.

DOVECOT_AUTH_BIND

Set this to yes to enable authentication binds (more details in the dovecot documentation). 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, 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!):

- LDAP_START_TLS=yes
- DOVECOT_TLS=yes
- SASLAUTHD_LDAP_START_TLS=yes

LDAP Setup Examples

???+ example "Basic Setup"

```yaml
version: '3.8'
services:
  mailserver:
    image: docker.io/mailserver/docker-mailserver:latest
    container_name: mailserver
    hostname: mail
    domainname: example.com

    ports:
      - "25:25"
      - "143:143"
      - "587:587"
      - "993:993"

    volumes:
      - ./docker-data/dms/mail-data/:/var/mail/
      - ./docker-data/dms/mail-state/:/var/mail-state/
      - ./docker-data/dms/mail-logs/:/var/log/mail/
      - ./docker-data/dms/config/:/tmp/docker-mailserver/
      - /etc/localtime:/etc/localtime:ro

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

??? example "Kopano / Zarafa"

```yaml
version: '3.8'

services:
  mailserver:
    image: docker.io/mailserver/docker-mailserver:latest
    container_name: mailserver
    hostname: mail
    domainname: example.com

    ports:
      - "25:25"
      - "143:143"
      - "587:587"
      - "993:993"

    volumes:
      - ./docker-data/dms/mail-data/:/var/mail/
      - ./docker-data/dms/mail-state/:/var/mail-state/
      - ./docker-data/dms/config/:/tmp/docker-mailserver/

    environment:
      # We are not using dovecot here
      - SMTP_ONLY=1
      - ENABLE_SPAMASSASSIN=1
      - ENABLE_CLAMAV=1
      - ENABLE_FAIL2BAN=1
      - ENABLE_POSTGREY=1
      - SASLAUTHD_PASSWD=

      # >>> SASL Authentication
      - ENABLE_SASLAUTHD=1
      - SASLAUTHD_LDAP_FILTER=(&(sAMAccountName=%U)(objectClass=person))
      - SASLAUTHD_MECHANISMS=ldap
      # <<< SASL Authentication

      # >>> Postfix Ldap Integration
      - ENABLE_LDAP=1
      - LDAP_SERVER_HOST=<yourLdapContainer/yourLdapServer>
      - LDAP_SEARCH_BASE=dc=mydomain,dc=loc
      - LDAP_BIND_DN=cn=Administrator,cn=Users,dc=mydomain,dc=loc
      - LDAP_BIND_PW=mypassword
      - LDAP_QUERY_FILTER_USER=(&(objectClass=user)(mail=%s))
      - LDAP_QUERY_FILTER_GROUP=(&(objectclass=group)(mail=%s))
      - LDAP_QUERY_FILTER_ALIAS=(&(objectClass=user)(otherMailbox=%s))
      - LDAP_QUERY_FILTER_DOMAIN=(&(|(mail=*@%s)(mailalias=*@%s)(mailGroupMember=*@%s))(mailEnabled=TRUE))
      # <<< Postfix Ldap Integration

      # >>> Kopano Integration
      - ENABLE_POSTFIX_VIRTUAL_TRANSPORT=1
      - POSTFIX_DAGENT=lmtp:kopano:2003
      # <<< Kopano Integration

      - ONE_DIR=1
      - DMS_DEBUG=0
      - SSL_TYPE=letsencrypt
      - PERMIT_DOCKER=host

    cap_add:
      - NET_ADMIN
```