For this guide, the following assumptions are made:
- MX Guarddog is being used to filter spam
- MX records have been set to MX Guarddog's servers
- Postfix successfully receives and delivers mail from MX Guarddog's servers
After following the instructions at MX Guarddog for setting up the MX records, email addresses, email server, and quarantine reports, everything should Just Work™. Spam should slow to a trickle; MX Guarddog does a really good job of spam filtering! The only thing they can't protect against is spammers that ignore the MX records of a server and try to connect directly to the server. For that, some configuration will need to be done. In addition to this, we'll also prevent submitting email on port 25 and only allow it on the submission port (587).
To restrict the clients which can connect to the SMTP port (25), you'll need the following configuration parameters in /etc/postfix/main.cf
:
/etc/postfix/main.cf
# TLS parameters
smtpd_tls_cert_file=/path/to/ssl.crt
smtpd_tls_key_file=/path/to/ssl.key
smtpd_use_tls=yes
smtpd_tls_auth_only=yes
# Enabling SMTP for authenticated users, and handing off authentication to Dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
# smtpd_sasl_auth_enable = yes
## Uncomment the following configuration to keep rejected mails queued instead of returning them to the sender. This
## is good for when you're initially turning this feature on and want to be sure you're not rejecting the wrong email.
# soft_bounce = yes
smtpd_recipient_restrictions =
reject_unauth_destination,
check_client_access hash:/etc/postfix/client_access,
reject
I placed all of this right before the myhostname
parameter. The first thing I did was enable TLS (smtpd_use_tls
) and make STARTTLS required for authentication (smtpd_tls_auth_only
). I'm using Dovecot for IMAP, so I configured Postfix to use Dovecot for user authentication. You'll also notice that I have the parameter to enable SASL authentication (smtpd_sasl_auth_enable
) commented out (the default value is no
). This has the effect of disallowing submission on port 25 since users aren't able to authenticate on that port. The smtpd_recipient_restrictions
parameter does a few things:
reject_unauth_destination
rejects unless the email's receipt can be relayed or this server is the final destinationcheck_client_access
checks the connecting client against a known list of IP addresses and performs the action specifiedreject
will reject any email that doesn't match either of the other two restrictions
The next step was to create /etc/postfix/client_access
with MX Guarddog's IP addresses:
/etc/postfix/client_access
# MX Guarddog's FQDN with all of its delivery server IP addresses
64.38.239.82 OK
64.38.239.83 OK
122.103.250.12 OK
64.38.239.86 OK
66.85.178.50 OK
85.195.83.79 OK
64.38.239.84 OK
64.38.239.85 OK
This file has to have postmap
run on it to turn it into a BerkelyDB file:
$ sudo postmap /etc/postfix/client_access
Postfix now is set up to only accept delivery on the SMTP port and reject submissions. In order to accept submissions on port 587, we'll need to edit /etc/postfix/master.cf
. Most distributions will have a default /etc/postfix/master.cf
with some lines commented out. Make sure to uncomment the line starting with submission
and comment out the line starting with smtps
. A lot of guides will tell you to enable that port because it is the official STARTTLS port, however the SMTPS port was never official and most clients can do STARTTLS over the submission port. I've added the configuration parameters for the submission port on the lines following the submission
line:
/etc/postfix/master.cf
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
smtp inet n - - - - smtpd
submission inet n - - - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_recipient_restrictions=permit_mynetworks,reject_non_fqdn_recipient,permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
#smtps inet n - - - - smtpd
Here's what I've done:
- Made it easier to differentiate between the SMTP port and the submission port in my logs (
syslog_name=postfix/submission
) - Required STARTTLS (
smtpd_tls_security_level=encrypt
) - Enabled authentication (
smtpd_sasl_auth_enable=yes
) - Permit sending from localhost and sending by authenticated users (
smtpd_recipient_restrictions=permit_mynetworks,reject_non_fqdn_recipient,permit_sasl_authenticated,reject
) - Added an identifier for mail filter programs such as Amavis (
milter_macro_daemon_name=ORIGINATING
)
Finally, restart postfix:
$ sudo service postfix restart
These settings will take the spam you receive from a trickle to a drip.
Hat tip to @jwr456 and @JBES for their initial ideas for the script
-
Create
/etc/postfix/update-client-access
with the following contents:#!/bin/bash set -e MXGD_IPS="$(/usr/bin/dig +short servers.ik2.com)" CONTENTS="" for ip in $MXGD_IPS; do CONTENTS="$CONTENTS$ip\tOK\n" done echo -e $CONTENTS > /tmp/client_access.in /usr/sbin/postmap /tmp/client_access.in mv /tmp/client_access.in /etc/postfix mv /tmp/client_access.in.db /etc/postfix/client_access.db
NOTE There is no need to reload
postfix
according to the docs:If you change a local file based database such as DBM or Berkeley DB, there is no need to execute "postfix reload". Postfix uses file locking to avoid read/write access conflicts, and whenever a Postfix daemon process notices that a file has changed it will terminate before handling the next client request, so that a new process can initialize with the new database.
-
Run the following commands:
sudo chmod 0700 /etc/postfix/update-client-access sudo /etc/postfix/update-client-access
-
Create
/etc/systemd/system/postfix-update-client-access.service
with the following contents:[Unit] Description=Update the Postfix client access database with MX Guarddog's IP addresses After=network-online.target [Service] Type=oneshot ExecStart=/etc/postfix/update-client-access ProtectHome=true ProtectSystem=true PrivateTmp=true
-
Run
sudo systemctl start postfix-update-client-access.service
and ensure that/etc/postfix/client_access.in
and/etc/postfix/client_access.db
are updated -
Create
/etc/systemd/system/postfix-update-client-access.timer
with the following contents:[Unit] Description=Monthly renewal of MX Guarddog's IP addresses [Timer] OnCalendar=monthly RandomizedDelaySec=1h Persistent=true [Install] WantedBy=timers.target
-
Enable the monthly timer by running the following:
sudo systemctl daemon-reload sudo systemctl enable postfix-update-client-access.timer sudo systemctl start postfix-update-client-access.timer
Postfix Hardening for MX Guarddog by Bryan Forbes is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Create a cron job to update /etc/postfix/client_access based on the answer section of dig -q servers.ik2.com and update the BerkleyDB file with postmap:
!/bin/bash
for x in
/usr/bin/dig +short servers.ik2.com
; do echo "$x OK"; done > /etc/postfix/client_access/usr/sbin/postmap /etc/postfix/client_access
/etc/init.d/postfix reload