Fail2ban on OpenBSD 6.0

If you have ever had a server exposed to the Internet, you will often see attempts to login to ssh on port 22.

After improving my log monitoring, these login attempts annoyed me enough to take action. So I installed Fail2ban.

Fail2ban monitors logs and will add ip addresses to your firewall to block based on rules. Fail2ban is written in Python and available for several platforms and can monitor different logs (not just ssh).

I have setup Fail2ban to watch for 3 failed logins (one failed login will allow 3 password attempts) and then block that IP address for 1 day.

The following instructions are for:

OpenBSD 6.0
Fail2ban 0.9.5

The instructions also assume that you have an OpenBSD server running with ssh port 22 exposed to the Internet and use Packet Filter (PF) for your firewall.

Installing Fail2ban

Install Python, when asked for version, select 3.5:

sudo pkg_add python

Download fail2ban-0.9.1.tar.bz2, uncompress and install:

cd ~/Downloads
wget https://github.com/fail2ban/fail2ban/archive/0.9.5.tar.gz
mv 0.9.5.tar.gz fail2ban-0.9.5.tar.gz 
tar -zvxf fail2ban-0.9.5.tar.gz
cd fail2ban-0.9.5
sudo python3.5 setup.py install
sudo mkdir /var/run/fail2ban

Next create a new rc file for Fail2ban. This will manage starting, stoping and checking for the status of Fail2ban. It is based on the rc.template, sabnzbd.rc and filebeat.rc.

http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/ports/infrastructure/templates/rc.template
http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/ports/news/sabnzbd/pkg/sabnzbd.rc
http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/ports/sysutils/beats/filebeat/pkg/filebeat.rc?rev=1.1.1.1&content-type=text/plain

It is worth noting that the rc file is a little non-traditional, because Fail2ban has two components, a client and a server. Normally rc files will start a daemon, check to see if the process is active and kill that process to stop. The `check` logic could probably be improved, but it works.

Create the rc file and paste in the content:

sudo vi /etc/rc.d/fail2ban
#!/bin/sh
#
# As the fail2ban-client is used to start the fail2ban-server, this rc is a little non-traditional.
#
# The rc_check looks for the fail2ban-server python thread (fail2ban-server as a parameter)
#
# The rc_stop can kill the fail2ban-server (The Nuclear Option) or the fail2ban-client (Polite Option).
#
#  pkill -f "fail2ban-server"
#
# Avoiding The Nuclear Option.

daemon="/usr/local/bin/fail2ban-client"

. /etc/rc.d/rc.subr

rc_bg=YES
rc_reload=NO
#pexp=fail2ban-server

rc_pre() {
	install -d -o root -m 0700 /var/run/fail2ban
}

rc_start() {
	$${rcexec} "${daemon} start ${daemon_flags} ${_bg}"
}

rc_check() {
	pgrep -q -f "fail2ban-server"
}

rc_stop() {
	${rcexec} "${daemon} stop"
}

rc_cmd $1

Set permissions:

sudo chmod 555 /etc/rc.d/fail2ban

Edit `/etc/rc.conf.local` to add the Fail2ban rc file:

sudo vi /etc/rc.conf.local
# ADDED 
pkg_scripts="fail2ban"

Configure Fail2ban

Need to configure fail2ban what an ssh login failure looks like. Please update `192.168.0.10` to your local server ip address.

A few comments here:
– Fail2ban is monitoring `/var/log/authlog`
– After an IP has 3 failed logins, the IP will be blocked
– The IP will be blocked for 1 day (86400 seconds)
– Exclude localhost IP

Create a new file `ssh-pf.local`:

sudo vi /etc/fail2ban/jail.d/ssh-pf.local
# NOTE: 192.168.0.10 is local ip
# NOTE:  3600 = 1 hr
# NOTE: 86400 = 1 day
[ssh-pf]
enabled  = true  
filter   = sshd  
action   = pf[localhost=192.168.0.10]
logpath  = /var/log/authlog
findtime  = 600
maxretry = 3
bantime  = 86400
ignoreip = 192.168.0.10

Configure fail2ban what action to take when the ssh login fails.

Existing configuration fail2ban for pf.conf is unchanged:

sudo vi /etc/fail2ban/action.d/pf.conf
# Fail2Ban configuration file
#
# OpenBSD pf ban/unban
#
# Author: Nick Hilliard <nick@foobar.org>
#
#

[Definition]

# Option:  actionstart
# Notes.:  command executed once at the start of Fail2Ban.
# Values:  CMD
#
# we don't enable PF automatically, as it will be enabled elsewhere
actionstart =


# Option:  actionstop
# Notes.:  command executed once at the end of Fail2Ban
# Values:  CMD
#
# we don't disable PF automatically either
actionstop =


# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
#
actioncheck =


# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:      IP address
#            number of failures
#          

Setup OpenBSD Packet Filter with a new table to store the banned ip addresses

NOTE: that table names are always enclosed in < > angled brackets

Edit `/etc/pf.conf` and add to end:

sudo vi /etc/pf.conf
# BEGIN ADDED fail2ban
# NOTE: ext_if is external interface device
ext_if="vio0"
table  persist
block quick proto tcp from  to $ext_if port ssh
# END ADDED fail2ban

Manage Fail2ban

Use rc scripts to manage:

sudo /etc/rc.d/fail2ban check
sudo /etc/rc.d/fail2ban start
sudo /etc/rc.d/fail2ban stop

Manually manage:

sudo fail2ban-client status
sudo fail2ban-client start
sudo fail2ban-client stop

Tail fail2ban log:

sudo tail -f /var/log/fail2ban.log

Print contents of table:

sudo pfctl -t fail2ban -Ts 

Start and load pf.conf:

sudo pfctl -e
sudo pfctl -f /etc/pf.conf

Conclusion

That’s it! It can be satisfying to login and print out the content of the PF fail2ban table and see the blocked IP addresses. Also, fewer spikes in the log monitoring of failed logins.

Comments are closed.