Nethence Newdoc Olddoc Lab Your IP BBDock  

Setting up a strong anti-spam MX with Postfix

Introduction

The Postfix config syntax changes depending on the version. I am using 3.1.0 here. Check with,

postconf -d|grep ^mail_ver

In this guide, the users' Maildir folders are possibly stored on a shared volume (NFS or shared disk fs), however the user db is still on the server itself into /etc/passwd. The best would be to switch mappings to MariaDB or something else for the running node to be independent from the data. Same goes if you are proceeding as a Docker container: it provides the application and is ideally data-independent.

Requirements

Make sure your system up-to-date,

apt update
apt -y full-upgrade
apt autoremove
dpkg -l | grep ^rc

Make sure you’ve got those installed,

apt -y install \
    postfix bsd-mailx rsyslog \
    postfix-policyd-spf-python
#mailutils pmailq

Postfix prep

Make some handy symlinks for operations (assuming this is a dedicated node or container),

cd ~/
ln -s ../home
ln -s ../etc/postfix
ln -s /etc/aliases
ln -s /var/log/mail.log
ln -s /var/log/mail.err

Backup the confs,

cd /etc/postfix/
cp -pi main.cf main.cf.dist
cp -pi master.cf master.cf.dist

and edit the configurations based on those examples,

vi main.cf

main.cf

vi master.cf

master.cf

Note that the Docker network 172.17.0.0/16 is added to mynetworks so e.g. the RBL checks won’t be performed against the MX server itself.

Note that myorigin is set to mydomain so you should tweak the /etc/passwd file and add some information about the user so you can more easyly determine where the automatically generated messages are coming from,

vipw

root:x:0:0:root@xc:/root:/bin/bash
WHEELED:x:1000:1000:WHEELED@xc,,,:/home/WHEELED:/bin/bash

The client_access file may look like this,

compute.amazonaws.com   REJECT compute.amazonaws.com is identified as a spam domain
.compute.amazonaws.com  REJECT compute.amazonaws.com is identified as a spam domain

postmap client_access

The helo.regexp file may look like this,

/^mx\.nethence\.com$/          550 you are not me
/^xc\.nethence\.com$/          550 you are not me
/^nethence\.com$/               550 you are not me

The sender_access file may look like (this is optional as it goes togeather with the unverified sender policy feature that is not enabled),

securityfocus.com       OK
online.net              OK
ovh.com                 OK

postmap sender_access

Allow Postfix to resolve hosts from its chroot land,

cd /var/spool/postfix/etc/
cp -pf /etc/resolv.conf /etc/hosts /etc/services ./

mkdir -p /var/spool/postfix/lib/x86_64-linux-gnu/
cd /var/spool/postfix/lib/x86_64-linux-gnu/
cp -vl /lib/x86_64-linux-gnu/libnss_* ./
ls -alhF
cd ~/

Make sure the mail users don’t get the dotfile skeletons,

mv -i /etc/skel/ /etc/skel.dist/
mkdir /etc/skel/

Don’t forget to tweak the system’s or container’s aliases e.g.,

cd /etc/
cp -pi aliases aliases.dist
vi aliases

root: real_mailbox_user
wheeleduser: root
abuse: root
contact: root
info: root
sales: root
hostmaster: root
www: root
webmaster: root
postmaster: root

newaliases

Ready for DNS

A + MX + TXT

You should publicly advertise a corresponding A record for the MX pointer, as a CNAME cannot used for that purpose. You cannot use a CNAME for the pointers covered by the SPF records either. It is not possible to have the same “Name” for a CNAME record and other records. So make sure your DNS settings are all good and SPF ready e.g.,

mx IN A PUBLIC_IP
mx2 IN A BKPMX_PUBLIC_IP

@ IN MX 10 mx
@ IN MX 20 mx2

* IN TXT "v=spf1 +mx ?a:some-smarthost -all"
@ IN TXT "v=spf1 +mx ?a:some-smarthost -all"

Note. +a:mx.nethence.com +a:mx2.nethence.com are optional as those IPs are already taken care of by the +mx SPF entry.

And check once those are populated (the delay mostly depends on the last records' TTL),

host -t mx nethence.com
host -t txt nethence.com
host -t txt spoof.nethence.com

host mx.nethence.com
host mx2.nethence.com

Refs.

PTR

If you want your MX to be able to send messages to other secure SMTPs on the public network, you might have to fix your own PTRs (sometimes done at the ISP side which is holding your IP address).

PUBLIC_IP IN PTR mx.nethence.com.
BKPMX_PUBLIC_IP IN PTR mx2.nehtence.com.

Ready to go

Create a mailbox (see Ops chapter below) for first-level acceptance.

If you stick to the provided init scripts (not a container), restart the thing,

service rsyslog restart
service postfix restart

otherwise (e.g. for a container),

rsyslogd
postfix start

Make sure the unix socker for SPF is up and running,

netstat -an|grep policy

Read the logs,

cd ~/logs.bash

#!/bin/bash
tail -n 25 -F /var/log/mail.*

chmod +x logs.bash
./logs.bash

while doing some testing from remote hosts (try with an authorized IP as well as from a should-be-blocked IP e.g. ADSL connection),

telnet xc.nethence.com 25
helo my.real.resolvable.remote.fqdn
mail from:<some.real@email>
rcpt to:<user@nethence.com>

and also try to send an email to yourself with an email client of course (is your smarthost is in the SPF?). And don’t forget to do a last telnet check against an SMTP open proxy service, just in case you messed up smtpd_relay_restrictions.

Don’t forget to enable Fail2ban to protect yourself from bot nets.

IMAP

See the fellow Dovecot guide.

Operations

GIT vs script

Eventually maintain the diffs if not using GIT,

    cd ~/
    wget http://doc.nethence.com/input/docker/postfix/confcheck.bash
    chmod +x confcheck.bash
    ./confcheck.bash

Applying minor Postfix configuration changes,

Within or outside a container,

postfix reload

Creating / Removing Mailboxes

Create a new mailbox,

new=<someuser>
#centos,
#useradd -g users -m -k /dev/null -s /sbin/nologin $new
#ubuntu,
useradd -g users -m -k /dev/null -s /dev/null $new
passwd $new
unset new

Note. The Maildir/ folder into the user’s homedir will be created by Postfix when the first mail arrives.

Remove a mailbox and loose its data,

userdel -r <someuser>

Manual REJECT

Deal with spam that eventually came through the hereby protections (wow, so that’s a clean spam!): look at the headers what fqdn connected to your MX and reject it manually so it doesn’t spam you again,

vi /etc/postfix/client_access

compute.amazonaws.com   REJECT compute.amazonaws.com is identified as a spam domain
.compute.amazonaws.com  REJECT compute.amazonaws.com is identified as a spam domain

postmap /etc/postfix/client_access

(Optional) False-positives

The unverified sender feature is not enabled. In case you do enable it, you need to deal with false-positives on the domains that do not pass tru the brutal verify-sender-against-all setting,

vi /etc/postfix/client_access

securityfocus.com       OK

postmap /etc/postfix/sender_access

Troubleshooting

If you get this error while starting Postfix,

postfix/postfix-script: warning: group or other writable: /usr/lib/postfix/./sbin/lmtp
...

==> don’t give a fuck about it, it’s complaining about symlinks' rights which point to files with OKAY permissions.

If you get this error quite often in the logs,

close database /var/lib/postfix/verify_cache.db: No such file or directory (possible Berkeley DB bug)

==> use proxy: in the address_verify_map statement as shown above.

Ref. http://www.postfix.org/ADDRESS_VERIFICATION_README.html

Backup / Secondary MX

Play with relay_domains, transport_maps and do NOT list example.com into mydestination.

References

References about anti-spam & RFC compliance

References for MariaDB mappings


Home | GitHub | Donate | Feedback