fail2ban with jails

Haven't tried with jails but seems like it would be straightforward. Install, make a configuration for each service, and start it up. Here is an example for /usr/local/etc/fail2ban/jail.d/bsdftp.conf on mine. Changing the log path to point inside a jail would be easy. Doing a search for specifying multiple "logpath" files showed this as the first result so it would seem like it's just a matter of specifying one for each jail: http://serverfault.com/questions/486301/how-to-set-up-fail2ban-to-read-multi-log-in-a-jail
Code:
[bsdftp]

enabled  = true
filter   = bsdftp
action   = pf
logpath  = /var/log/auth.log
bantime  = 1800
findtime = 1800
maxretry = 5
 
Yep, just run fail2ban on the host and reference the files inside the jails (/jails/myjail/var/log/auth.log for example).
 
BTW, my next goal: multiple actions for a given jail.d entry. Anyone done that? e.g. if something is doing nasty stuff on the website, block them from both http and ssh.
 
  • Thanks
Reactions: Oko
I use fail2ban extensively with PF to block SSH, SASL, Dovecot, and Postfix brute-force and DoS attacks. I also have custom-made scripts to log all permanent banned IP addresses so PF can reload the blacklist when restarted. It works very well. I plan to add Nginx to block scanners, spiders or requests for sensitive or missing files.

Need to be careful about http as http requests could be legitimate. You can limit concurrent connections to single IP address via PF or Nginx config to block http DoS attacks. Once that concurrent connection reaches its max then you can permanent ban that IP address.
 
I use fail2ban extensively with PF to block SSH, SASL, Dovecot, and Postfix brute-force and DoS attacks. I also have custom-made scripts to log all permanent banned IP addresses so PF can reload the blacklist when restarted. It works very well. I plan to add Nginx to block scanners, spiders or requests for sensitive or missing files.

Need to be careful about http as http requests could be legitimate. You can limit concurrent connections to single IP address via PF or Nginx config to block http DoS attacks. Once that concurrent connection reaches its max then you can permanent ban that IP address.

Could you please post the configuration files or a link to your blog when you explain things? Thank you!
 
BTW, my next goal: multiple actions for a given jail.d entry. Anyone done that? e.g. if something is doing nasty stuff on the website, block them from both http and ssh.

I've just been blocking all traffic once someone hits it enough to trigger an action by Fail2Ban. That is accomplishing what you mentioned. It's just the pf.conf rule below. Are you currently doing something more more fine grained than this?

Code:
block drop in log quick on $wan_ifs from <fail2ban> to any
 
... I also have custom-made scripts to log all permanent banned IP addresses so PF can reload the blacklist when restarted. ...

For this in particular, security/py-fail2ban gained support for using a SQLite database for persistent storage of banned addresses. I just checked the Freshports change log and that was introduced in the 0.9.0 update in May of 2014. So you may be able to save some effort not duplicating that functionality with a custom script.
 
Could you please post the configuration files or a link to your blog when you explain things? Thank you!

My scripts are still in development but it works for now. Feel free to modify or improve them if you wish.

Need to include this otherwise it will not work.
/etc/pf.conf
Code:
# Tables
table <fail2ban> persist file "/etc/pf.blacklist"

# Fail2ban
block in log quick on $ext_if from <fail2ban> to any

SSH - use custom pf to temporary ban and unban IP addresses.
pf-offender - IP address permanently banned after 3 temporary bans.
/usr/local/etc/fail2ban/jail.local
Code:
[DEFAULT]
bantime = 3600
findtime = 604800
maxretry = 3

[sshd]
enabled  = true
filter  = bsd-sshd
action  = pf
logpath  = /var/log/auth.log
  /jails/web/var/log/auth.log

[pf-offender]
enabled  = true
filter  = pf-offender
action  = pf-offender
logpath  = /var/log/fail2ban.log
bantime  = -1

Custom pf script to ban and unban IP addresses.
/usr/local/etc/fail2ban/action.d/pf.local
Code:
[Definition]

actionban  = /usr/local/etc/fail2ban/scripts/pf-offender.sh add <ip>
actionunban  = /usr/local/etc/fail2ban/scripts/pf-offender.sh delete <ip>

Custom script to add IP to blacklist
/usr/local/etc/fail2ban/action.d/pf-offender.local
Code:
[Definition]

actionban  = /usr/local/etc/fail2ban/scripts/pf-offender.sh blacklist <ip>

This script monitors fail2ban's temporary bans from ssh, sasl, postfix, dovecot, etc.
/usr/local/etc/fail2ban/filter.d/pf-offender.local
Code:
[INCLUDES]

before  = common.conf

[Definition]

_daemon  = pf-offender
failregex  = NOTICE  \[\S*\] Ban <HOST>

ignoreregex =

This script is still in development and it works. It creates two pf blacklist files in /etc directory. Text file pf.blacklist is used by PF to repopulate PF table after restart or reload. Another text file pf.blacklist.txt is created for logging history of permanent banned IP addresses. The reason why I created separate blacklist file is because PF needs clean IP list to repopulate the PF table without the dates. Don't forget to chmod +x pf-offender.sh.
/usr/local/etc/fail2ban/scripts/pf-offender.sh
Code:
#!/bin/tcsh

set cmd  = $1
set ip  = $2
set file  = `grep -c $ip /etc/pf.blacklist`
set table  = `pfctl -t fail2ban -T show | grep -c $ip`
set date  = `date +"%Y-%m-%d"`

# add temp banned ip to pf table
if ( $cmd == "add" && "$table" == "0" ) then
  pfctl -t fail2ban -T add $ip
endif

# delete temp banned ip from pf table
if ( $cmd == "delete" && "$file" == "0" ) then
  pfctl -t fail2ban -T delete $ip
endif

# add permanent banned ip to pf table and blacklisted file
if ( $cmd == "blacklist" && "$file" == "0" ) then
  # add ip if not found in table
  if ( "$table" == "0" ) then
  pfctl -t fail2ban -T add $ip
  endif
  echo $ip >> /etc/pf.blacklist
  echo $date - $ip >> /etc/pf.blacklist.txt
endif

# populate permanent banned ip to pf table from blacklist file
# this is not needed as pf uses the blacklist file
if ( $cmd == "populate" ) then
  foreach line ( "`cat /etc/pf.blacklist`" )
  pfctl -t fail2ban -T add $line
  end
endif

Hope this helps.
 
For this in particular, security/py-fail2ban gained support for using a SQLite database for persistent storage of banned addresses. I just checked the Freshports change log and that was introduced in the 0.9.0 update in May of 2014. So you may be able to save some effort not duplicating that functionality with a custom script.

I'm not aware of this changes but my script does more and gives me the flexibility to modify the blacklist file if needed. I do get many IP addresses that are similar so I modify the blacklist with a blanket ban on IP addresses to keep the list short.
 
SirDice dvl Works like a charm with jails, however how I can ensure that the fail2ban service is only started after jails are started?

I get a boot time message from fail2ban saying that the path to my log files hasn't been found, my guess is that the nullfs file system of the jail hasn't been mounted yet at that point.

I am using cbsd and using the following path: /home/cbsd-jails/jails/myjail/var/log/messages, I'd have expected such an absolute to be accessible from the host even if the jail is not mounted yet.

Right now, because of this startup error, I have to start the fail2ban service manually after every reboot, which is annoying since I prefer to have everything start automatically on boot.
 
SirDice dvl Works like a charm with jails, however how I can ensure that the fail2ban service is only started after jails are started?

Alter this line, append jail:

sh:
[11:37 zuul dan ~] % grep REQUIRE /usr/local/etc/rc.d/fail2ban
# REQUIRE: DAEMON

Confirm the order via:

sh:
rcorder /etc/rc.d/* /usr/local/etc/rc.d/*

Ensure

jail appears before fail2ban - the amendment will require repeating after each reinstall of fail2ban.
 
Alter this line, appending jail:

sh:
[11:37 zuul dan ~] % grep REQUIRE /usr/local/etc/rc.d/fail2ban
# REQUIRE: DAEMON

Confirm the order via:

sh:
rcorder /etc/rc.d/* /usr/local/etc/rc.d/*

Ensure

jail appears before fail2ban - the amendment will require repeating after each reinstall of fail2ban.

Thank so you so much, it is working:

Code:
$ grep REQUIRE /usr/local/etc/rc.d/fail2ban
# REQUIRE: DAEMON jail
$ rcorder /etc/rc.d/* /usr/local/etc/rc.d/*
...
/usr/local/etc/rc.d/cbsdd
/etc/rc.d/jail
/etc/rc.d/securelevel
/usr/local/etc/rc.d/fail2ban

FreeBSD is such a pleasure to work with and get things done. When I discover such amazing features I realize how little I actually leverage the power and flexibility of this OS. What's funny is that everything is made so easy by default that this is enough to cover enterprise needs without needing arcane knowledge of the OS.
 
Last edited by a moderator:
I am using cbsd and using the following path: /home/cbsd-jails/jails/myjail/var/log/messages, I'd have expected such an absolute to be accessible from the host even if the jail is not mounted yet.

~cbsd/jails/myjail is mountpoint for jail rootfs. However, in fact, the file is located in ~cbsd/jails-data/myjail-data directory. Just use /home/cbsd-jails/jails-data/myjail-data/var/log/messages.
 
Back
Top