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_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
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
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,
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
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.
Optional TLS-related security changes.
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
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