on fail2ban and docker
Here is a weird one.
I have a server exposing web ports to the internet. As most (all?) servers
do, this one gets a fair amount of scans ant things that don’t really add any
value to me. Mostly nmap
path enumerations and other kinds of scripts
looking for something that was never there.
I’d like them not to. Since that’s not really up to me, I’d like to block them.
I already use fail2ban to block any brute force
attempt on the ssh
service on the same server, so it clearly it should be easy peasy.
Right?
Caddy
I use Caddy as the web server, mostly because it has
stupid-easy to deploy tls certificates.
Caddy
encoders are not really fail2ban-friendly: console encoder
is not really
meant to output to a file - and json encoder
outputs… json, fail2ban
is regex
based, so you can make it work, but it’s not ideal.
But it’s what I have, so it’s what I’ll do.
Fail2ban filter
I found some regex online that said that worked on the standard caddy
logs, but none really filtered.
Digging in, the problem was not on the regex on the log line, but on the pattern for the date.
In the end, i made it work with something like this, that matched the timestamp logged from caddy
:
[user@localhost]# cat /etc/fail2ban/filter.d/caddy.conf
[Definition]
failregex = ^.*"remote_ip":"<HOST>",.*?"status":(?:401|403|500),.*$
datepattern = ^.*"ts":{EPOCH}\.
[user@localhost]#
a tip - fail2ban
has an utility - fail2ban-regex
made exactly for this.
The documentation could be friendlier, but all the info is there.
after trying this, fail2ban
recognized the entries on the log file, and
deployed the ban action… but not really. The server was still available
to the offending origin.
…back to the drawing board.
Docker
My instance of caddy
runs on a docker
container.
docker
does all it’s networking magic on iptables
.
I found a couple of issues on github
related to docker, and they pointed me to the
wiki, where it says that you should change the iptables
chain
great! lets do that:
[user@localhost]# cat /etc/fail2ban/jail.d/caddy.local
[caddy]
enabled = true
port = http,https
filter = caddy
logpath = /var/logs/caddy_logs/access.log
maxretry = 10
findtime = 1h
bantime = 24h
chain = DOCKER-USER
one restart later… and still no ban.
but I had a clue… there was no blocking rule on iptables -L
Fail2ban and firewalld
I checked and checked fail2ban configuration.
The default clearly stated that the ban-action was deployed by touching iptables
rules:
[user@localhost]# grep -e "^banaction" /etc/fail2ban/jail.conf
banaction = iptables-multiport
banaction_allports = iptables-allports
(...)
[user@localhost]#
Since I had not configured a special action
on the fail2ban side, this is where I expected the block to be.
But it was not there.
On my system (Centos 9 Stream) firewalld
is also running (actually, it’s the default!).
I’m not conversant enough on iptables
to mind on way over the other, but since it’s
the default, I’m not keen on removing it, not without understanding the problem.
At this point, I was clear that fail2ban
was blocking by way of firewalld
. But I could not find out why.
It took me way more time than I care to admit to find it, but find it I did.
It does that by adding a file that modifies the default rules:
[user@localhost]# cat /etc/fail2ban/jail.d/00-firewalld.conf
# This file is part of the fail2ban-firewalld package to configure the use of
# the firewalld actions as the default actions. You can remove this package
# (along with the empty fail2ban meta-package) if you do not use firewalld
[DEFAULT]
banaction = firewallcmd-rich-rules
banaction_allports = firewallcmd-rich-rules
[user@localhost]#
This file was right next to the configuration for the caddy
ban, but I had not payed any attention to it!
two banaction
s later on the caddy
jail definition, and the block was finally working:
[user@localhost]# cat /etc/fail2ban/jail.d/caddy.local
(...)
banaction = iptables-multiport
banaction_allports = iptables-allports
[user@localhost]#
sometimes it comes easy.
but not this time.