Posted: 2025-04-14 21:05:39 by Alasdair Keyes
I've been running a mail server for about 20 years. For years I was using Exim (https://www.exim.org/) but due to one-too-many high security CVEs I decided to switch to Postfix (https://www.postfix.org/) about 2 years ago.
One thing that any mail server admin will attest to is that your server is constantly probed by bots trying to access mailboxes and send emails.
I store mail logs for ten weeks and in that time over half a million failed login attempts.
# zgrep 'SASL LOGIN authentication failed' /var/log/mail.log* | wc -l
570813
Even with logrotate and compressed logs, this is starting to take up a fair amount of disk space, mainly through the un-compressed logs before logrotate starts zipping them up.
I decided to install fail2ban (https://github.com/fail2ban/fail2ban) to kurb this. fail2ban is a tool that scans logs in real-time for lines that indicate probes/attacks and ban the IPs using the firewall. In their terminology a filter
scans the logs for lines indicating an attack and a jail
takes action of some kind to block the IPs.
I used to use fail2ban years ago when I first started managing servers, but stopped using it well over a decade ago as I wasn't finding it too much help at the time.
After installation, noticed that my specific setup with Postfix using saslauthd for SMTP authentication is not captured by the standard fail2ban Postfix filter.
A standard line in my logfile looks like...
2025-04-10T15:49:08.591090+01:00 myhostname postfix/smtpd[55089]: warning: unknown[1.2.3.4]: SASL LOGIN authentication failed: authentication failure, sasl_username=probedemail@domain.com
Instead of trying to bodge the existing filter/jail, I decided I'd write my own to detect just these lines. With a bit of trial and error I came up with the following two config files...
/etc/fail2ban/filter.d/custom-postfix-auth.conf
# Fail2Ban filter for Postfix with SASL auth failures
#
#
[Definition]
failregex = warning:\s+\S+\[<HOST>\]: SASL [A-Z\-\d]+ authentication failed: authentication failure, sasl_username=.*$
ignoreregex =
journalmatch = _SYSTEMD_UNIT=postfix@-.service
datepattern = {^LN-BEG}Epoch
{^LN-BEG}
# Author: Alasdair Keyes
/etc/fail2ban/jail.d/custom-postfix-auth.conf
[custom-postfix-auth]
enabled = true
maxretry = 30
bantime = 86400
backend = systemd
findtime = 86400
banaction = iptables-allports
Once these were in place I ran a test, this shows that it does indeed detect 64383 entries in the current log file.
# fail2ban-regex systemd-journal /etc/fail2ban/filter.d/custom-postfix-auth.conf
Running tests
=============
Use failregex filter file : custom-postfix-auth, basedir: /etc/fail2ban
Use datepattern : {^LN-BEG}Epoch
{^LN-BEG} : Default Detectors
Use systemd journal
Use encoding : UTF-8
Use journal match : _SYSTEMD_UNIT=postfix@-.service
Results
=======
Failregex: 9562 total
|- #) [# of hits] regular expression
| 1) [9562] warning:\s+\S+\[<HOST>\]: SASL [A-Z\-\d]+ authentication failed: authentication failure, sasl_username=.*$
`-
Ignoreregex: 0 total
Date template hits:
Lines: 44414 lines, 0 ignored, 9562 matched, 34852 missed
[processed in 2.96 sec]
Missed line(s): too many to print. Use --print-all-missed to print all 34852 lines
I reloaded fail2ban systemctl reload fail2ban
and can now see I'm starting to block those troublesome IPs.
# fail2ban-client status custom-postfix-auth
Status for the jail: custom-postfix-auth
|- Filter
| |- Currently failed: 8
| |- Total failed: 9
| `- Journal matches: _SYSTEMD_UNIT=postfix@-.service
`- Actions
|- Currently banned: 3
|- Total banned: 3
`- Banned IP list: 1.2.3.4 40.50.60.70 6.7.8.9
If you found this useful, please feel free to donate via bitcoin to 1NT2ErDzLDBPB8CDLk6j1qUdT6FmxkMmNz
© Alasdair Keyes
I'm now available for IT consultancy and software development services - Cloudee LTD.
Happy user of Digital Ocean (Affiliate link)