Hardening Postfix

While there are plenty of good (and not so good) anti-spam solutions available, most of them cost a bit of money in terms of purchasing and licensing fees. Even without a dedicated appliance, there are several ways you can harden the Postfix MTA against spam and other internet nasties. In this article, we’re going to look at some ways of hardening postfix that I’ve found effective.

The things that we’re going to do, are designed to either reject messages or delay accepting messages from hosts that behave in a suspicious way, hosts that appear on blacklists somewhere or hosts that we have not seen before.
Before diving into this post, you may wish to look at an older post I’ve done, that explains in some detail how to set up a Postfix MTA with amavisd-new and spamassassin as a front-end for MS Exchange. It’s a bit outdated now, but the concept is still valid. That post was written for openSUSE, this time, we’re using Ubuntu 14.04 LTS.
The methods we’ll use are as follows:

  • Setting postfix restrictions
  • Enabling blacklist checks
  • Greylisting
  • DKIM verification
  • Sender Policy Framework (SPF)

You may wonder why we’re going to harden postfix if we can set up a virus scanner and spam detection like spamassassin. The rationale for that is simple: hardening postfix makes sense because it is on the front line. Anything we stop at the level of the MTA doesn’t need to be passed onto a virus scanner or a spam filter, saving resources like CPU time and memory. It’s much more efficient keeping dirt out than trying to clean it away once it is already inside the system.

Hardening Postfix by setting restrictions

One of the first, easiest steps to hardening postfix, is to make it a bit more strict with the kind of connections it is willing to deal with. We can set several restrictions on clients and messages that improve our ability to reject malicious hosts and unwanted messages. You should set the following options in /etc/postfix/main.cf.

smtpd_recipient_restrictions = reject_invalid_hostname,
                               reject_non_fqdn_hostname,
                               reject_non_fqdn_sender,
                               reject_unauth_destination,
                               reject_unknown_sender_domain,
smtpd_helo_required = yes
smtpd_helo_restrictions = permit_mynetworks,
                          reject_non_fqdn_helo_hostname,
                          reject_invalid_helo_hostname,
strict_rfc821_envelopes = yes
smtpd_delay_reject = yes
disable_vrfy_command = yes
smtpd_data_restrictions = reject_unauth_pipelining

What all these parameters do and whether they will suit your specific needs, is beyond the scope of this article. For a detailed explanation of all the configuration options you can set in main.cf, please see the official documentation. These options will make Postfix more strict on the type of connections it allows and what kind of messages it will accept. This will filter out poorly written spam robots, malformed email messages and email from domains that do not resolve properly. Take note however, that you might also block some legitimate messages from poorly written, non RFC compliant software!

Hardening Postfix by enabling blacklist checks

Another fairly easy thing to do to harden postfix, is make it check senders against lists of known offenders. There are many blacklists which may be enabled but the two I use are Spamcop and SORBS. They are trivial to implement and yield immediate and noticeable results.

We’ve set several recipient restrictions above. Let’s expand these with the blacklist checks of Spamcop and SORBS. When you are done, your smtpd_recipient_restrictions should look like this.

smtpd_recipient_restrictions = reject_invalid_hostname,
                               reject_non_fqdn_hostname,
                               reject_non_fqdn_sender,
                               reject_unauth_destination,
                               reject_unknown_sender_domain,
                               reject_rbl_client bl.spamcop.net,                                reject_rbl_client dnsbl.sorbs.net,

From now on, every incoming connection will be checked against these blacklists, which will result in a considerable drop in spam.

Hardening postfix by enabling greylisting

Greylisting is a technique used to delay the acceptance of inbound email. This means it is halfway between whitelisting and blacklisting, hence greylisting. Basically, when an MTA connects to deliver mail and we’ve not seen that MTA before, Postfix will tell the MTA to try again later. A proper MTA will honour this request and will try to deliver the email at various, increasing intervals. Spammers have limited time to complete their spam runs before their MTA gets added to blacklists so often it won’t bother delivering mail again when it gets turned away. Presto, their spam message won’t be delivered!

While greylisting can be a very useful tool to implement and should be transparent to end users (all the delaying happens between MTA’s), it might cause problems with email from scripts that try to deliver mail directly instead of handing it off to an MTA. This may cause messages of that kind to be lost since the script will not retry sending the message.

Setting up greylisting is a bit more work than the first two steps but still fairly easy to do. It’s not installed by default when you install Ubuntu 14.04, so you’ll have to add it by hand with the command below.

$ sudo apt-get install postgrey

This should pull in postgrey and all its dependencies. Next, we have to set up Postfix to use postgrey. Again, we need to do this in /etc/postfix/main.cf in the familiar smtpd_recipient_restrictions section. First, we need to check at which port postgrey will be listening for connections from Postfix, though. On Ubuntu, we can find the postgrey configuration file in /etc/default. For Ubuntu 14.04, the default postgrey port is 10023. To plug it into Postfix, we need to add the parameters in red below.

smtpd_recipient_restrictions = reject_invalid_hostname,
                               reject_non_fqdn_hostname,
                               reject_non_fqdn_sender,
                               reject_unauth_destination,
                               reject_unknown_sender_domain,
                               reject_rbl_client bl.spamcop.net,                                reject_rbl_client dnsbl.sorbs.net,
                               check_policy_service inet:192.168.178.2:10023

After this, Postfix will have to be reloaded for the changes to become active. For more information, please see this article from the Ubuntu community.

I found that I needed to specify the local IP address in front of the listening port in /etc/default/postgrey for things to work. My postgrey config file looks as below.

# postgrey startup options, created for Debian

# you may want to set
#   --delay=N   how long to greylist, seconds (default: 300)
#   --max-age=N delete old entries after N days (default: 35)
# see also the postgrey(8) manpage

POSTGREY_OPTS="--inet=192.168.178.2:10023 --delay=199 --auto-whitelist-clients=5 --greylist-text"
POSTGREY_OPTS="$POSTGREY_OPTS --whitelist-clients=/etc/postgrey/whitelist_clients"
POSTGREY_OPTS="$POSTGREY_OPTS --whitelist-recipients=/etc/postgrey/whitelist_recipients"

# the --greylist-text commandline argument can not be easily passed through
# POSTGREY_OPTS when it contains spaces.  So, insert your text here:
POSTGREY_TEXT="Sorry, your mail server has been greylisted for five minutes. Please come back later."

Hardening Postfix by using DKIM

DKIM or DomainKeys Identified Mail is a method for email authentication. While it is not used by all, it can still be a good thing to check for because it will help you to reject messages that have their sender domain forged.

I won’t go into the details of how to set up DKIM for Postfix on Ubuntu because it is well-documented by the Ubuntu community. I will attest for its usefulness though. Setting it up is not trivial and will require some time.

Hardening Postfix by using SPF

SPF or Sender Policy Framework allows domain owners to add a record in their DNS zone file, specifying which servers are authorised to send email for their domain. Mail administrators who have enabled SPF can check this SPF DNS record to check if a connecting MTA is indeed authorised for the domain it claims to be handing mail for. If the connecting MTA doesn’t match the SPF record, we can be sure that the MTA is not authorized (or the SPF record is badly configured).

Again, I will not go into the details of explaining how to enable SPF checking on Postfix, because the Ubuntu community has already done that work. I will say that I have opted for the Python program, not the Perl program because I found it easier to set up. The functionality should be the same, though.

Conclusion

If you’ve done all 5 steps above, you’ll have succeeded in hardening Postfix quite a bit, made your system less accepting of spam and other unwanted messages, saved system resources and money as well. I’d still want to invest time in adding virus scanning and spam filtering to my MTA but at the very least you’ll have saved those instruments some work.

I hope you’ve found this article helpful. If you have comments or if you have tips on hardening postfix that you’d like to add, feel free to leave a comment below.