LibreLAMP Postfix TLS Configuration

This page assumes familiarity with the terminology defined on the main Mail Server Page.

This page assumes you have configured Unbound as a local DNSSEC caching resolver as described on the Unbound Page.

Do not only consult this documentation.

You should also consult the official Postfix documentation, specifically:

Also, the Postfix user list can often help if an Internet search does not answer your question.

This article does not cover every TLS use case, not even close. I mention this because the official Postfix documentation really should be read before running a Postfix server. Their documentation sometimes can be confusing during the first read, read it more than once and things will likely start to click.

Please not that if you are upgrading to the LibreLAMP packaging of Postfix and have modified your existing /etc/postfix/main.cf file, the LibreLAMP default configuration will be installed as /etc/postfix/main.cf.rpmnew and you will need to migrate changes.

A Brief Hopefully Mostly Correct History of SMTP Port Usage

SMTP not only predates TLS, it predates the World Wide Web. Like the HTTP protocol, TLS is a bolt-on addition when used with SMTP. Differences between HTTP and SMTP logistics presents some differences in how it is bolted on.

Originally, both Mail Transfer Agents and Mail Users Agents used TCP Port 25 to send a message to an MTA using the SMTP protocol. There was no encryption.

When encryption was initially bolted on to SMTP, it used TCP Port 465. Administrators would often use a program called stunnel to use SMTP over TLS and it was known as SMTPS, adding the ‘S’ for ‘Secure’, similar to HTTPS. With Port 465, encryption was always used and was negotiated as soon as the connection was made. Port 25 lacked encryption, Port 465 always had encryption. Just like with HTTP Port 80 lacks encryption and Port 443 always has encryption.

During the late 1990s / early 2000s, the STARTTLS command changed all of that. I am not an Internet historian and even though I did read the mail lists back then, my memory as to why it changed is absent, but it changed.

Opportunistic TLS

STARTTLS is used for what is called Opportunistic TLS, a concept I am not very fond of.

Opportunistic TLS is based on the philosophy that the communication itself is more important than whether or not the communication is done with a secure channel. Use a secure channel if you can, but communicate anyway if you can not use a secure channel.

The way Opportunistic TLS works, the initial communication is done with plain text. When the client MUA or MTA connects to the server MTA, the initial connection does not have any security, it is plain text. If the server supports TLS and is configured correctly the server then responds listing STARTTLS as an available feature:

[alice@host ~]$ telnet librelamp.com 25
Trying 2600:3c01::f03c:91ff:fee4:310c...
Connected to librelamp.com.
Escape character is '^]'.
220 librelamp.com ESMTP Postfix
EHLO mail.domblogger.net
250-librelamp.com
250-PIPELINING
250-SIZE 10240000
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 SMTPUTF8

In that telnet example, after I sent the EHLO mail.domblogger.net command, the server responded with a list of features it supports, including STARTTLS.

When the client sees the STARTTLS feature is supported, it knows the server is capable of encryption. The client can then send the STARTTLS command and the server and client then attempt to upgrade their connection protocol from plain text to encrypted. If they can negotiate a secure connection, the session continues encrypted. If they can not negotiate a secure connection, the session continues in plain text.

The flaw in Opportunistic TLS is that it is fairly trivial for an attacker to prevent the TLS upgrade from ever happening. Simply remove the STARTTLS from the plain text server response and the connection remains plain text. Most people call this a downgrade attack, but that is incorrect. The session was simply tricked into never upgrading.

With STARTTLS, Port 25 soon became a port that is only used for MTA to MTA communication. While it still can be used for authenticated MUA connections, it is considered bad practice. Many Internet Service Providers actually block outgoing Port 25 to prevent compromised end user machines from behaving as open spam relays and a properly configured MTA will not allow authentication on Port 25.

So TCP Port 587 was designation for authenticated MUA message submission.

Like Port 25, it uses SMTP but it differs in that it requires the client to authenticate or the connection is dropped. Also like Port 25, it uses Opportunistic TLS.

This resulted in Port 465 being dropped from the standards, though it was still used by many service providers for submission that was encrypted from the start.

As of RFC 8314 Port 465 has been brought back as an official port and is preferred to Port 587.

Thus the current state of SMTP port usage:

TCP Port 25
Used for MTA to MTA communication. Required to accept plain text communication, the communication may be upgraded to secure if both the client (sending) MTA and server (receiving) MTA support encryption and an attacker has not stripped the STARTTLS command.
TCP Port 587
Used for authenticated MUA communication with an MTA. If both the MUA and MTA support encryption and an attacker has not stripped the STARTTLS command, the connection is secure. The server may (and should) be configured to reject connections that are not upgraded to use encryption. This port may also be used for MTA to MTA communication when authentication from the sending MTA is required.
Port 587 is still commonly used but is in the process of being deprecated in favor of Port 465 which always uses encryption.
TCP Port 465
Same purpose as Port 587 except encryption is explicitly required, reducing the odds of client and sever configuration mistakes resulting in a plain text transmission of the authentication data.

For an MTA listed in an MX record, it MUST listen on Port 25.

I recommend using Port 465 for MUA message submission. If you currently use Port 587, run both but notify users they should update their client configuration, with an end date when Port 587 will no longer be supported.

TLS and SMTP

Port 587 and 465 when properly configured on the server require an encrypted connection. Connecting to either of those ports securely is a solved problem. Mistakes in configuration can of course happen, but when properly configured, the server should reject plain text communication other than the initial STARTTLS used to initiate encryption on Port 587.

With Port 25, the SMTP RFC literally requires that you accept plain text communication.

As a test, I did run one server that broke the RFC and rejected plain text. The result is I did not receive some messages I should have. The spam received was also greatly reduced, a bonus. Most of the non-spam messages I did not receive were notices from various WordPress blogs I had commented on, it seems common for WordPress hosting services to use qmail as their SMTP and qmail is an abandoned outdated project that does not support encryption.

But there were other messages I missed too, including some that were important. Every message that was rejected, I tried convincing the companies behind them to fix their outgoing mail, but my pleas were largely ignored. I do not know what it takes to get these companies to do the right fricken thing so we can finally start rejecting incoming mail that is not encrypted and only lose less then 1% of non spam as a result. I wish I did know what to do.

For now, encryption on Port 25 can really only be enforced on the sending side of things, with hints from the receiving server on what to do.

Opportunistic Securing of SMTP on Port 25

The first thing an MTA should do when sending a message to the receiving MX host is to check and see if the receiving MX MTA has deployed DANE. If it has deployed DANE then only send the message if encryption is used AND the x.509 certificate matches the DANE fingerprint (digest).

To accomplish this in Postfix, you need to have a DNSSEC enforcing recursive resolver running on your SMTP server, as described on the Unbound Page.

Once you have unbound properly set up, the following directives in your Postfix /etc/postfix/main.cf will instruct Postfix to enable DANE enforcement:

[root@host ~]# postconf -e "smtp_dns_support_level = dnssec"
[root@host ~]# postconf -e "smtp_tls_security_level = dane"
[root@host ~]# postfix reload

That will provide you with opportunistic DANE enforcement. If the receiving server is set up for DANE, it will be enforced and messages will only be sent if encryption is used and the x.509 certificate validates against the fingerprint in the TLSA record for TCP Port 25 of the receiving MTA.


For additional security measures, please see Postfix PKI Security (internal site link), specifically the section on STARTTLS Everywhere: /PostfixPKI-Security#postfixstarttls.

TLS Version and Cipher Suite Philosophy

Historically in the SMTP server world, there has been the philosophy that weak cryptography is better than no cryptography. As the SMTP RFC requires MX servers to accept communication in plain text, compatibility with weak ciphers was more secure when MTA clients that only supported weak ciphers tried to connect than having those servers use plain text.

Furthermore, MTA clients did not bother to check the validity of MTA server x.509 certificates. It simply was not logical to do so. If the certificate failed validation, they would just send the message in plain text which is less secure than connecting with to a server with a certificate that did not validate.

Opportunistic TLS fosters a culture of lazy security. This is why I do not like it.

The result of Opportunistic TLS was support for weak obsolete ciphers and rampant use of expired x.509 certificates that often did not even match the host name. It was common place, and dangerous because e-mail is often how passwords for things like bank accounts were reset.

Within the last few years, several factors have allowed things to change for the better.

DNSSEC provided meaningful security to DNS responses. Building upon DNSSEC, DANE provided a robust mechanism for validating a server x.509 certificate that was completely independent of the flawed PKI system. Fraudulently signed certificates that pass PKI validation with flying colors do not pass DANE validation even if the attacker is able to modify DNS responses.

Building upon DANE, DANE for SMTP provided a robust standardized mechanism for taking the ‘Opportunistic’ out of Opportunistic TLS. When an MTA server provides a TLSA record for TCP Port 25, an MTA client that enforces DANE for SMTP must not send the message plain text. The x.509 certificate MUST validate against the TLSA record. When plain text is no longer the fallback if encryption can not be negotiated, it is no longer logical to continue supporting weak ciphers.

Independent of DNSSEC, major attacks on the PKI system resulted in vast improvements. OCSP provided a proper mechanism for clients to verify that signed certificates have not been revoked. OCSP stapling provided a scalable way for OCSP to function, even during outages of the Certificate Authority’s OCSP server. Certificate Transparency has made it much easier to detect fraudulently issued certificates and revoke them. DNS-CAA has provided a mechanism companies can use to limit who is allowed to sign certificates for their assets, making fraudulent certificates more difficult for an attacker to obtain.

The AES-NI instruction set has made the AES ciphers with their forward secrecy very fast and ubiquitous. Publicly exposed major flaws in SSLv2 and SSLv3 and publicly exposed weaknesses in TLS 1.0 has resulted in many lazy system administrators finally adopting TLS 1.2. A common system administrator saying: “If it ain’t broke, don’t fix it.” Well, when it is publicly demonstrated just how broken it really is and has been, motivation to fix it is strong. Your job depends upon it.

MTA-STS, like DANE for SMTP, is providing a standardized mechanism for taking the ‘Opportunistic’ out of Opportunistic TLS.

The point of all this blabbering: 2019 is the year to put a stake in the now outdated philosophy that ‘Weak Cryptography is better than Plain Text.’

2019 is the year we phase out TLS 1.0/1.1 so we can stop using them completely by 2021.

2019 is the year we stop supporting cipher suites without forward secrecy completely. Send the message that if Forward Secrecy is not used, we should not have the delusion it is secure, so use Forward Secrecy or Plain Text when connecting. There are no other valid options.

2019 is the year when we increase the advertisement of MX servers (through DANE, MTA-STS, and STARTTLS Everywhere) that MTA clients should only connect to if there is a secure, verified channel using high quality modern validated encryption.

Postfix MTA Server TLS Configuration

If you are only using Postfix as an MTA client (the typical use scenario on most websites) to send messages to other servers, you can skip this section.

For x.509 certificate generation instructions, please see the Postfix TLS Certificate Generation page.

Most of these configuration parameters start with smtpd_ in the setting name. Note the presence of the d.

These parameters are set in the /etc/postfix/main.cf configuration file. You can edit that file manually or you can use the postconf -e command.

smtpd_tls_cert_file
This parameter specifies the full path to your RSA x.509 certificate. The LibreLAMP default configuration has it set to /etc/pki/tls/certs/postfix.pem which is a self-signed certificate and should be replaced. It is automatically generated upon install and really only exists to make sure there is one. Even if you will be using a self-signed certificate, you should replace it with one that matches the host name clients will be connecting to.
smtpd_tls_key_file
This parameter specifies the full path to the RSA private key associated with the RSA x.509 certificate. The LibreLAMP default has it set to /etc/pki/tls/private/postfix.key which is a private key automatically generated upon install and really only exists to make sure there is one. It should be replaced.
smtpd_tls_CAfile
This parameter specifies the full path to the so-called ‘Certificate Bundle’ (sometimes called ‘Chain’) that contains intermediary x.509 certificates between the Certificate Authority root and your signed RSA certificate.
By default this parameter is commented out. Please leave it that way. With Postfix, it is better to append the certificate bundle to the end of the file that contains the certificate.
smtpd_tls_security_level
This parameter has two logical value options: may and encrypt. When set to may (the default), Opportunistic TLS is used. The server will announce it supports STARTTLS and the client may initiate encryption.
When set to encrypt the server will reject connections that do not use encryption. This breaks the SMTP RFC when used on an MX server with Port 25. Last time I looked at statistics, roughly 10% of non-spam e-mail was still being relayed by the client MTA to the MX MTA without encryption. When that statistic is closer to 2% it may be safe to start breaking the RFC.
In certain industries where privacy is more critical it may be appropriate to break the RFC now just to protect those sending e-mail through a mis-configured MTA that either does not attempt to encrypt at all or only supports outdated encryption. One could argue that such scenarios really should be using end to end encryption before the message is even sent (e.g. PGP or S/MIME) but the unfortunate reality is that tools to set those up are not very user friendly. I have even met medical doctors with degrees from the finest medical schools who could not figure out how to set up their e-mail client to safely use those end to end solutions.
Most servers though should leave this set to the default of may for the time being or you will have issues with some e-mail not being delivered to your users. They can get cranky when they do not get messages they expect to receive. Even call you names when you explain why and then complain to your boss. It is not pretty.
smtpd_tls_loglevel
This parameter specifies how much logging of TLS activity is performed. It takes an integer argument between 0 and 4 inclusive. The LibreLAMP default configuration sets this value to 1. See the TLS_README file for descriptions of the log levels.
Please note that a log level of 3 should only be used when trouble-shooting an issue, and a log level of 4 should probably only be used by developers debugging changes to the code.
smtpd_tls_received_header
When set to yes and smtpd_tls_loglevel is set to a level of at least 1, Postfix will include information about the TLS protocol and cipher used in the Received: header of the e-mail. The default value for this setting in the LibreLAMP Postfix configuration is set to yes.
smtpd_tls_exclude_paranoid
This is not an official directive. It is only intended to have meaning in the context of SMTP Submission (local site link).
It defines a strict set if ciphers to exclude intended to be used with the submission service running on Port 465 or on Port 587. MX servers listening on Port 25 have to be more liberal with the TLS cipher suites they allow or mail is not delivered to your users, but the submission ports should only be used by clients who authenticate themselves, often with an account specific password. At this point it is reasonable to assume every user either has a mail client capable of TLS 1.2 with support for ECDHE cipher suites, or can update to one.
By default this is set to DES, 3DES, CAMELLIA, SHA, DH, RSA which would result in restricting submission clients to a small handful of high quality ciphers.
If that list ends up being too restrictive, try removing DH from the list. That line excludes DHE key exchange ciphers. If it is still is too restrictive, try removing the SHA restriction. That excludes the TLS 1.0/1.1 ciphers that use the deprecated SHA1 digest algorithm.
smtpd_tls_exclude_ciphers
This is a comma delimited list of patterns in cipher suites to match against, instructing Postfix to NOT use those ciphers.
This is an official directive and defines ciphers to exclude when Postfix is being used in the context of an MX server that receives connections from an MTA client.
The LibreLAMP default has this set to DES, 3DES, RC4, RSA, aNULL which while it still allows the deprecated TLS 1.0/1.1 ciphers, it only allows ciphers that use Forward Secrecy (ECDHE and DHE key exchange).
smtpd_tls_dh1024_param_file
This tells Postfix where the DH parameters are that it should use for DHE key exchange. The parameter name contains dh1024 in the parameter name for historic reasons only.
The default for LibreLAMP has it configured to use /etc/pki/tls/dh4096.pem which are 4096-bit DH parameters. In LibreLAMP that parameter file is regenerated once a month. Other safe options to use include /etc/pki/tls/dh2048.pem and /etc/pki/tls/dh3072.pem. The reason I have it set to 4096-bit by default, many consider it best practice to never use DH parameters smaller than the RSA key size when using DHE key exchange. 2048-bit however would probably be safe.
If you prefer the ‘Official RFC 3525’ DH groups, in LibreLAMP Postfix you can also use the /etc/pki/tls/MODP-IKE-2048-group14.pem, /etc/pki/tls/MODP-IKE-3072-group15.pem, /etc/pki/tls/MODP-IKE-4096-group16.pem, /etc/pki/tls/MODP-IKE-6144-group17.pem, or /etc/pki/tls/MODP-IKE-8192-group18.pem DH groups.
If you comment this directive out, Postfix will use built-in parameters which I believe are identical to the RFC 3525 Group 14 2048-bit parameters. That is probably safe, I am not aware of any known attacks against the parameter groups defined in that RFC that are at least 2048-bit.
Under no circumstances should you ever use DH parameters below 2048-bit. Hopefully by 2021 it will be safe to just disable DH key exchange all together, but even though a small minority, some clients still in use do not support the superior ECDHE key exchange. This is particularly still true in developing countries.
tls_preempt_cipherlist
This parameter tells Postfix to insist upon its internal cipher order when negotiating upon a cipher suite to use with a connecting MTA client. This should always be set to yes so that the strongest available cipher is used. When the client picks, it often is not the best.

For an MX server, you can test the quality of your Postfix configuration at https://www.hardenize.com/.

You also should make sure it is not open relay. You can test that at https://mxtoolbox.com/diagnostic.aspx.

Postfix MTA Client TLS Configuration

If you are using Postfix as an MTA client (the typical use scenario on most websites) to send messages to other servers, you definitely need to pay attention to this section. A lot of web servers get this wrong.

All of these configuration parameters start with smtp_ in the setting name. Note the lack of the d.

These parameters are set in the /etc/postfix/main.cf configuration file. You can edit that file manually or you can use the postconf -e command.

smtp_tls_CApath
This is a directory where PEM format x.509 root certificates for Certificate Authorities you want Postfix to trust are stored. LibreLAMP ships with the Mozilla bundle of trusted Certificate Authorities, it is the most widely used bundle in the Free Libre Open Source Software world, and is also the bundle of Certificate Authorities used by the STARTTLS Everywhere project when they validate a mailbox domain.
For LibreLAMP I do not directly extract them from Mozilla, I extract them from https://curl.haxx.se/docs/caextract.html.
smtp_tls_security_level
This parameter determines whether or not Opportunistic TLS should be used. With the default value of may it will attempt to use TLS if available, and send the message in plain text if a secure connection can not be established.
I highly recommend changing this to dane if you can.
Before setting to dane your operating system must use a DNSSEC enforcing recursive resolver, preferably running on the same host. You can achieve this on CentOS/RHEL 7 (and virtually every server operating system) easily with Unbound.
When set to dane the smtp_dns_support_level must be set to dnssec. When set to dane the smtp_host_lookup must be set to dns.
When set to dane the behavior falls back to the Opportunistic TLS behavior of may if the MTA server you are connecting to does not publish a DNSSEC secured TLSA record, and it falls back to encrypt if a TLSA record exists but is not usable.
The security level for specific mailbox domains can be specified in a map file to override this setting and is discussed on the Postfix PKI Security page.
smtp_tls_mandatory_ciphers
For connecting to other MTA servers, Postfix has four classes of ciphers it will offer for the server to select from: EXPORT, LOW, MEDIUM, and HIGH. These lists are updated within the Postfix source itself and which ciphers belong in which lists sometimes changes from version to version. Each grade also includes the ciphers in all higher grades.
The EXPORT grade ciphers should never be used and are not even supported by LibreSSL. The LOW grade ciphers are weak and generally should not be used. The HIGH grade are the best but require the MX server Postfix is connecting to has a modern TLS stack, unfortunately many do not.
For this reason, Postfix in LibreLAMP defaults to MEDIUM.
As with smtp_tls_security_level, the mandatory cipher level for specific mailbox domains can be specified in a map file to override this setting and is discussed on the Postfix PKI Security page.
smtp_tls_note_starttls_offer
This directive tells Postfix to log whether or not the remote MTA server offers TLS. It can be useful information to have when reading the log files, so it defaults to yes in LibreLAMP.
#smtp_dns_support_level = dnssec
This is required for DANE support, but in turn, it requires that the recursive resolver used by your operating system supports DNSSEC so it is commented out by default.
If you have Unbound running on the server like you should and you have the operating system configured to use it as the name resolver as you should, then make sure this directive is un-commented.
smtp_host_lookup = dns
This directive is also required for DANE support and must include dns for DANE support. By default it is set to dns.
smtp_tls_loglevel
Similar to smtpd_tls_loglevel but for logging outgoing connections. LibreLAMP default is set to 1. Level of 3 or 4 should not be used on production servers.
#smtp_tls_policy_maps = hash:/etc/postfix/starttls_everywhere_policy
This directive can be used to point to a Postfix map of mailbox domains with per-domain TLS policies defined that override the defaults.
This is used by the LibreLAMP starttls-everywhere package (see /PostfixPKI-Security#postfixstarttls) to define mailbox domains that require a secure channel of either DANE or PKI validation of the MX host and TLS 1.2 better level of encryption.
By default this directive is not active.