7. Advanced Postfix configuration

Postfix offers a lot of interesting features that are beyond the scope of this document; we will examine just a few, mostly security-related, that may be necessary depending on the environment where Postfix is operating.

7.1 Enabling TLS

Enabling TLS support in Postfix allows you to encrypt SMTP sessions and SASL authentication exchanges and to optionally authenticate remote SMTP clients and/or servers. However, keep in mind that, by enabling TLS support, you also turn on thousands and thousands of lines of OpenSSL library code. Assuming that OpenSSL is written as carefully as Wietse's own code, every 1000 lines introduce one additional bug into Postfix [TLS]. Therefore, if you think you don't need these features, feel free to skip this paragraph.

TLS relies on public key certificates for authentication and therefore requires that you first set up a basic Public Key Infrastructure (PKI) for managing digital certificates. As a preliminary step, we will create the directories where certificates will be stored:

# install -m 700 -d /etc/postfix/ssl/private

The first step in setting up the PKI is the creation of the root CA certificate (/etc/ssl/ca.crt) and private key (/etc/ssl/private/ca.key) using openssl(1):

# openssl req -days 3650 -nodes -new -x509 -keyout /etc/ssl/private/ca.key \
> -out /etc/ssl/ca.crt
[ ... ]
Country Name (2 letter code) []: IT
State or Province Name (full name) []: Italy
Locality Name (eg, city) []: Milan

Organization Name (eg, company) []: Kernel Panic Inc.
Organizational Unit Name (eg, section) []: Postfix CA
Common Name (eg, fully qualified host name) []: ca.lan.kernel-panic.it
Email Address []: <enter>

The next step is the creation of the private key (/etc/postfix/ssl/private/server.key) and Certificate Signing Request (/etc/postfix/ssl/private/server.csr) for the mail server:

# openssl req -days 3650 -nodes -new -keyout /etc/postfix/ssl/private/server.key \
> -out /etc/postfix/ssl/private/server.csr
[ ... ]
Country Name (2 letter code) []: IT
State or Province Name (full name) []: Italy
Locality Name (eg, city) []: Milan

Organization Name (eg, company) []: Kernel Panic Inc.
Organizational Unit Name (eg, section) []: Postfix Server
Common Name (eg, fully qualified host name) []: mail.kernel-panic.it
Email Address []: <enter>

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: <enter>
An optional company name []: <enter>


Finally, the CA will generate the signed certificate out of the certificate request:

# openssl x509 -req -days 3650 -in /etc/postfix/ssl/private/server.csr \
> -out /etc/postfix/ssl/server.crt -CA /etc/ssl/ca.crt \
> -CAkey /etc/ssl/private/ca.key -CAcreateserial

Signature ok
subject=/C=IT/ST=Italy/L=Milan/O=Kernel Panic Inc./OU=Postfix Server/CN=mail.kernel-panic.it
Getting CA Private Key

If you want the mail server to authenticate SMTP clients, you can generate any number of client certificates by repeating the last two steps.

To actually turn on TLS support in Postfix, we need to add a few parameters to the /etc/postfix/main.cf configuration file:

# Enable (optional) TLS encryption
smtpd_tls_security_level = may
# Enable logging of TLS handshake and certificate information
smtpd_tls_loglevel = 1

# TLS certificates
smtpd_tls_cert_file = /etc/postfix/ssl/server.crt
smtpd_tls_key_file = /etc/postfix/ssl/private/server.key
smtpd_tls_CAfile = /etc/ssl/ca.crt

# External entropy source for the pseudo random number generator pool.
# Specify /dev/arandom when /dev/urandom gives timeout errors.
tls_random_source = dev:/dev/urandom

and uncomment the smtps service in /etc/postfix/master.cf(5):

smtps     inet  n       -       -       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING

Finally, we can reload Postfix configuration to apply the changes made:

# postfix reload
postfix/postfix-script: refreshing the Postfix mail system

7.2 SMTP authentication with SASL

When configuring Postfix, we have restricted mail relay to a limited number of trusted networks, i.e. the internal corporate LANs. Sometimes, however, such a relay policy may not fit your organization's requirements: a typical example is the need to let mobile users (such as sales people) send messages from anywhere over the Internet.

In these cases, the best solution to allow relay from legitimate users (while still blocking UCE software) is certainly using SMTP authentication, by means of the SASL protocol (defined in [RFC4954]). However, there are some downsides to enabling SASL authentication: it will force us to unchroot the smtpd(8) process and, since the Cyrus SASL library is a lot of code, Postfix will become as secure as other mail systems that use the Cyrus SASL library (see [SASL]). So, if you don't need this feature, feel free to skip this paragraph.

To enable SASL authentication in Postfix, we just have to add a few parameters in the /etc/postfix/main.cf configuration file:

# Enable SASL authentication in the Postfix SMTP server
smtpd_sasl_auth_enable = yes

# Only accept mail from trusted networks, authenticated clients or mail with
# a 'RCPT TO' address that Postfix is forwarder or final destination for
smtpd_recipient_restrictions = permit_mynetworks permit_sasl_authenticated 

# Enable inter-operability with old SMTP clients
broken_sasl_auth_clients = yes

# Name of the Postfix SMTP server's local SASL authentication realm
smtpd_sasl_local_domain = $mydomain

SASL configuration parameters must be contained in a file named smtpd.conf, located in /usr/local/lib/sasl2. The SASL library will rely on Courier's authdaemond process as the authentication backend (the MySQL backend only supports passwords stored in clear-text):

pwcheck_method: authdaemond
authdaemond_path: /var/run/courier-auth/socket
mech_list: PLAIN LOGIN

Next, we need to edit the /etc/postfix/master.cf(5) file to make smtpd(8) run unchrooted (just put a "n" in the process's chroot field):

smtp      inet  n       -       n       -       -       smtpd
[ ... ]

and reload Postfix configuration.

# postfix reload
postfix/postfix-script: refreshing the Postfix mail system

Finally, we can perform a simple test to make sure everything works as expected. Authentication information is sent as the base64-encoding of the string "\0username\0password", where "\0" is the null byte.

$ perl -MMIME::Base64 -e 'print encode_base64("\0d.mazzocchio\@kernel-panic.it\0danix");'
$ telnet mail.kernel-panic.it 25
Connected to mail.kernel-panic.it.
Escape character is '^]'.
220 mail.kernel-panic.it ESMTP Postfix
EHLO somedomain.org
250-SIZE 10240000
250 DSN
235 2.0.0 Authentication successful
221 2.0.0 Bye
Connection closed by foreign host.