Securing Postfix With TLS

Thursday, March 31, 2022 • 5 minutes to read

Encrypting data transfer over HTTP protocol is slowly becoming a common practice. Web browsers vendors, general security knowledge, and services like Let’s Encrypt help a lot. There are, of course, a lot of legacy systems with no encryption or an insecure configuration. However, in my opinion, the situation is a lot better than with the good, old, simple mail transfer protocol. So, if you have an SMTP service and it is not yet secured with TLS, you should do it, especially since it is not as straightforward as it seems initially.

How to enable TLS encryption in Postfix?

To enable TLS encryption for the Postfix server, you need a certificate, a private key, and only three configuration parameters. You can create a self-signed certificate, buy a standard SSL/TLS certificate from any of Certificate Authorities (CA), or use Let’s Encrypt service. If you have decided to use Let’s Encrypt, the command you need is certbot certonly --standalone -d mail.example.com.

The first two parameters you need to add in the main.cf configuration are smtpd_tls_cert_file and smtpd_tls_key_file, which should point to your certificate and private key. Additionally, you need to set smtpd_tls_security_level as opportunistic or mandatory. But if your SMTP server should receive e-mails through the Internet, you should use may, which means opportunistic.

The above configuration parameters will enable TLS when Postfix acts as an SMTP server but not if it is a client for another remote SMTP server. You will need to set one more configuration parameter, the smtp_tls_security_level. Once again, if it is a machine available on the Internet, choose may value. Please be careful. The first option starts with smtpd_, the second with smtp_.

The configuration will look like the below one:

smtpd_tls_cert_file = /etc/pki/tls/certs/postfix.pem
smtpd_tls_key_file = /etc/pki/tls/private/postfix.key
smtpd_tls_security_level = may
smtp_tls_security_level = may

Yes, it is the whole configuration. But we need to clarify two things.

Opportunistic TLS vs. Mandatory TLS.

When you choose to use smtpd_tls_security_level = may in your configuration, the server will announce to remote clients that it supports STARTTLS but will not require TLS encryption if the remote client is not supporting it. It is called an opportunistic TLS. Similarly, when set smtp_tls_security_level = may, the client will try to use TLS if remote server supports it, otherwise it will use plaintext.

Mandatory TLS, the encrypt value in any of the above configuration parameters, means that either server or client will require a TLS connection and will not connect if the remote client or server does not support it. According to the RFC 2487, it must not be applied on publicly available SMTP servers. Therefore, you can imagine that it may break connectivity between servers.

Is the default TLS setup of Postfix secure?

Well, yes, but only kind of. At least in the version 3.5.x. This version default values for smtpd_tls_ciphers, smtp_tls_ciphers, smtpd_tls_mandatory_ciphers, and smtp_tls_mandatory_ciphers is medium. What does it mean? It means that tls_medium_cipherlist = aNULL:-aNULL:HIGH:MEDIUM:+RC4:@STRENGTH. That is not bad, the only real problem here are enabled RC4 ciphers. Additionally, smtpd_tls_protocols, smtpd_tls_mandatory_protocols, smtp_tls_protocols, and smtp_tls_mandatory_protocols are set to !SSLv2, !SSLv3. It means we are still supporting TLS in version 1 and 1.1.

In general, it is good. The configuration is not vulnerable to the most popular SSL/TLS attacks, like Heartbleed, POODLE, LOGJAM. Still, as we are using TLS1, some attacks are possible.

How to make Postfix TLS configuration more secure?

First of all, let’s log the summary message of the TLS handshake. It will help you monitor your configuration. Additionally, you may want to log the hostname of a remote SMTP server that offers STARTTLS but does not enable TLS. To do this, add the following lines to your main configuration file:

smtpd_tls_loglevel = 1
smtp_tls_loglevel = 1
smtp_tls_note_starttls_offer = yes

Now, let’s review the protocols and ciphers you are using. Unless you need to support some very old clients (like Java 7 or older), allow only TLS v1.2 and TLS v1.3 protocols. Instead of using standard medium ciphers, let’s use forward secrecy and authenticated cipher suites. There are based on intermediate compatibility server-side TLS settings provided by Mozilla. Here are the following settings that you need to add to the main.cf file:

smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
tls_medium_cipherlist = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384

Next, make sure you do not allow TLS renegotiation. It can reduce opportunities for a potential CPU exhaustion attack. You will need to add tls_ssl_options = NO_RENEGOTIATION configuration parameter.

Since Postfix 3.1, the compiled-in default prime is 2048-bits long. It is used with non-export EDH ciphers and may be beneficial if you generate your prime. For older versions, this is a must. Generate it with openssl dhparam -out /etc/pki/tls/private/postfix.dh.param 2048, and then add it to the main configuration with smtpd_tls_dh1024_param_file = /etc/pki/tls/private/postfix.dh.param.

Optionally, you can enable adding to the receive header information about the protocol, cipher, remote SMTP client, and issuer certificate CNs. The parameter that you need is smtpd_tls_received_header = yes. It is not guaranteed that other servers will not modify that information in transit. So you need to consider that if you want to enable it.

The second optional change is to force Postfix to use the server’s cipher preference order instead of the client’s order. Usually, it is the client’s decision, but some of them could be not cleaver enough and try to negotiate weaker ciphers, even though they support the better ones. The option to enable it is tls_preempt_cipherlist = yes. Additionally, it allows you to support weaker ciphers for a broken client if needed but use the best available cipher for everyone else.

TLS, SASL, and the submission service.

If you use submission service and SASL authentication, you should consider force encryption in that service by changing the TLS security level (parameter smtpd_tls_security_level) to encrypt. Additionally, make Postfix to not announce SASL authentication over unencrypted connections (parameter smtpd_tls_auth_only). You should add those changes to your master.cf configuration file to ensure they are enabled only for submission service.

The following example of entries in the master.cf file will be sufficient.

submission inet n       -       n       -       -       smtpd
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_tls_security_level=encrypt
  -o smtpd_tls_auth_only=yes
operationspostfixlinuxencryptioncertificate
See Also
This site uses cookies to analyze traffic and for ads measurement purposes according to your browser settings. Access to those cookies is shared with Google to generate usage statistics and detect and address abuse. Learn more about how we use cookies.