DEBOPS.POSTLDAP(5)

NAME
debops.postldap - Configure Postfix SMTP service to use Virtual Mail with LDAP support

SYNOPSIS

debops run service/postldap [--limit group,host,...] [--diff] [--check] [--tags tag1,tag2,...] [--skip-tags tag1,tag2,...] [<ansible-playbook options>] ...

DESCRIPTION

The debops.postldap Ansible role can be used to configure and manage a Postfix Virtual Mail server with an LDAP backend. It allows configuration of Postfix using Ansible inventory variables.

GETTING STARTED

  Default configuration

The debops.postldap role configures a Postfix SMTP server with support for a virtual user mail system, i.e. where the senders and recipients do not correspond to the Linux system users. Hence it is possible to host emails for other domains. The users, email alias and domains will be managed with LDAP. This role use the organization defined in the mailservice schema setup by debops.slapd by default. The schema is designed to use the 'mail' LDAP attribute as an uniqueness constraint for the mailAddress, mailAlternateAddress and other attributes across LDAP entries. The 'mail' attribute itself is not used in e-mail service operation. For example, the following LDAP entry sets the user user1 with user1@mydomain.net <user1@mydomain.net> as main address and alias1@mydomain.net <alias1@mydomain.net> as alias.

objectClass: inetOrgPerson
objectClass: mailRecipient
objectClass: authorizedServiceObject
authorizedService: all
mail: user1@mydomain.net
mailAddress: user1@mydomain.net
mailAlternateAddress: alias1@mydomain.net

Local mail is enabled by default, support for mail aliases is provided by the debops.etc_aliases Ansible role and the LDAP user attribute mailAlternateAddress.

From a single address it is also possible to deliver the message to several recipients by using the mailAlias structural object to define a standalone e-mail aliases:

objectClass: mailAlias
objectClass: authorizedServiceObject
authorizedService: all
mail: alias@mydomain.net
mailAddress: alias@mydomain.net
mailForwardTo: user1@mydomain.net
mailForwardTo: user2@mydomain.net

It is also possible to attach an email existing entity using the 'mailDistributionList' auxiliary object:

objectClass: organizationalUnit
objectClass: mailDistributionList
objectClass: authorizedServiceObject
authorizedService: all
ou: IT Department
mail: itdept@mydomain.net
mailAddress: itdept@mydomain.net
mailForwardTo: admin1@mydomain.net
mailForwardTo: admin2@mydomain.net

The mailAddress attribute of the different objects will ensure that the address is unique in the mail system.

This role only works when LDAP support is explicitly enabled and the environment has a working LDAP infrastructure. See the debops.ldap role and its documentation for more details about setting up LDAP client support on a host.

  Overriding lookup table configuration

The Postfix LDAP lookup tables defined by the debops.ldap Ansible role are designed to work with the LDAP directory set up by the debops.ldap and debops.slapd roles. If you want to use different LDAP directory configuration, or tailor the default configuration to your own needs, you can override specific parameters in the looup table configuration via the Ansible inventory.

The role defers to the debops.postfix Ansible role for actual looup table configuration and passes the details via the role dependent variables. You can find more about the details in the postfix__lookup_tables documentation.

For example, if you want to change the LDAP filter of the ldap_virtual_recipients.cf lookup table, you can defined in the Ansible inventory:

# ansible/inventory/host_vars/mail-server/postfix.yml
postfix__host_lookup_tables:
  - name: 'ldap_virtual_recipients.cf`
    state: 'append'
    query_filter: '(&(|(mail=%s)(mailAlias=%s)))'

Please note that the configuration is defined in the postfix__* variables, not postldap__* variables. It is also important to use the append state to make sure that the configuration is only applied when the debops.postldap configuration is "active".

If you want to disable a part of the LDAP configuration defined in the Ansible inventory, you can change the state to ignore, which will then use the definition from the role defaults.

Avoid any other states in this case, because the resulting configuration will be applied in different contexts, for example when you run the debops.postfix role directly, and will break your configuration.

After making your changes, you can apply them by running the command:

debops run service/postldap -l mail-server -t role::postfix --diff

This will execute the debops.postfix role in the context of the debops.postldap role and correct set of variables will be active.

  Example inventory

To install and configure Postfix Virtual Mail Server on a host, it needs to be present in the [debops_service_postldap] Ansible inventory group:

[debops_service_slapd]
ldap-server
[debops_service_postfix]
mail-server
[debops_service_postconf]
mail-server
[debops_service_postldap]
mail-server

The debops.postldap playbook configures only the LDAP part of postfix configuration, you should use the debops.postfix role and its playbook to set up Postfix mail server. Additional useful configuration can be found in the debops.postconf role.

  Example playbook

If you are using this role without DebOps, here's an example Ansible playbook that uses the debops.postldap role:

---
- name: Manage Postfix service with Virtual Mail LDAP backend
  collections: [ 'debops.debops', 'debops.roles01',
                 'debops.roles02', 'debops.roles03' ]
  hosts: [ 'debops_service_postldap' ]
  become: True
  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'
  pre_tasks:
    - name: Prepare postfix environment
      ansible.builtin.import_role:
        name: 'postfix'
        tasks_from: 'main_env'
      vars:
        postfix__dependent_packages:
          - '{{ postldap__postfix__dependent_packages }}'
        postfix__dependent_lookup_tables:
          - '{{ postldap__postfix__dependent_lookup_tables }}'
        postfix__dependent_maincf:
          - role: 'postldap'
            config: '{{ postldap__postfix__dependent_maincf }}'
      tags: [ 'role::postfix:env', 'role::postfix', 'role::postldap', 'role::secret', 'role::ferm' ]
  roles:
    - role: secret
      tags: [ 'role::secret', 'role::postfix', 'role::postldap' ]
      secret__directories:
        - '{{ postfix__secret__directories }}'
    - role: postldap
      tags: [ 'role::postldap', 'skip::postldap', 'role::postfix' ]
    - role: ldap
      tags: [ 'role::ldap', 'skip::ldap' ]
      ldap__dependent_tasks:
        - '{{ postldap__ldap__dependent_tasks }}'
    - role: postfix
      tags: [ 'role::postfix', 'skip::postfix' ]
      postfix__dependent_packages:
        - '{{ postldap__postfix__dependent_packages }}'
      postfix__dependent_lookup_tables:
        - '{{ postldap__postfix__dependent_lookup_tables }}'
      postfix__dependent_maincf:
        - role: 'postldap'
          config: '{{ postldap__postfix__dependent_maincf }}'

  Ansible tags

You can use Ansible --tags or --skip-tags parameters to limit what tasks are performed during Ansible run. This can be used after a host was first configured to speed up playbook execution, when you are sure that most of the configuration is already in the desired state.

Available role tags:

role::postldap
    Main role tag, should be used in the playbook to execute all of the role tasks as well as role dependencies.

POSTFIX CONFIGURATION GUIDES

Here you can find a few guides that can help you configure more advanced Postfix features. Some of these can and are implemented as separate Ansible roles, here you can see the configuration specific to debops.postfix role.

  Configure Postfix as a Virtual User Mail System

This guide describes how to set up a virtual user mail system, i.e. where the senders and recipients do not correspond to the Linux system users.

It requires a working LDAP infrastructure (See debops.ldap and debops.slapd) in order to manage and authenticate the users and get the corresponding email address and aliases. It is also possible to configure accounts with wildcard (catch-all) email addresses. The default configuration uses first the aliases set by debops.etc_aliases and then queries the LDAP server, if no match was found.

See also debops.dovecot and debops.roundcube for an IMAP server and Email-Webclient correspondingly.

The following example shows a real-world™ setup on the Hetzner Cloud. It consists of two servers, one controller and a mail-server. The LDAP directory is hosted also in the controller. mail-server has access to LDAP over an internal network (10.10.10.0/28) attached directly to the VMs. This setup has no internal DNS server (no split-DNS), thus internal IPs are mapped to DNS entries in the form $service.hetzner.mydomain.net.

ansible/inventory/group_vars/hetzner/ldap.yml

---
# Enable LDAP, as is deactivated by default
ldap__enabled: True
ldap__domain: 'mydomain.net'

ansible/inventory/host_vars/skynet.mydomain.net/slapd.yml

---
## Network access to OpenLDAP server
# Firewall Settings
#   Block connections to the OpenLDAP via system firewall and TCP Wrappers from any host (aka Internet);
#   Hosts that can connect must be specified via the slapd__*_allow variables.
slapd__accept_any: false
slapd__group_allow:
  # Hetzner internal network
  - '10.10.10.0/28'

ansible/inventory/host_vars/mail-server.mydomain.net/pki.yml

---
### Create TLS Certs for the mail server
#
# In order to sign the cert by Let's Encrypt CA install nginx in the 'mail-server',
# so that the acme script can work.
pki_host_realms:
  - name: 'mail.mydomain.net'
    acme: false
    domains:
      - 'mail.mydomain.net'
      - 'smtp.mydomain.net'
      - 'imap.mydomain.net'
      - 'mail-server.mydomain.net'

ansible/inventory/host_vars/mail-server.mydomain.net/postfix.yml

---
# basic Postfix SMTP server with configuration similar to the "Internet Site"
# MTP service listens for connections on port 25 from all hosts.
# Mail relay is authorized from localhost, other hosts are deferred.
postfix__domain: 'mydomain.net'
postfix__pki_realm: 'mail.mydomain.net'

AUTHOR
Rainer 'rei' Schuth

COPYRIGHT
2014-2024, Maciej Delmanowski, Nick Janetakis, Robin Schneider and others