So a couple of years ago, I got tired of all the brute force ssh attacks
on my servers.
I wasn't particularly worried about anybody getting in: on most
of my boxes, there are only one or two allowed logins, and I restrict who
can log in using the AllowUser parameter in
/etc/ssh/sshd_config. There are also other safeguards in place.
Still, if someone has unsuccessfully tried 30 times to log in as "root"
on my box, I'd like to avoid having them come into contact with any of
my hosts, so enter SSHGuard.
SSHGuard, along with its more well known brethren, DenyHosts and
Fail2ban, all work roughly the same way. They monitor your logs, and
if they see some predetermined number of failed logins, they block the
ip.
The devil is in the details. They all vary on what kind of logs they can
parse. They all can parse ssh logs, but some can also handle Apache
logs, mail logs, ftp logs etc. They all seem to be able to talk to
iptables directly, but others can also understand pf, ipfw,
etc.
For a couple of years, I used DenyHosts on my FreeBSD box. It was a pain
to setup, and as I found a few months ago, didn't work properly.
DenyHosts parsed auth.log well enough, the problem was that it
didn't speak pf. So in order to get it to work with pf, I had to
write wrapper scripts. The interface was easy enough, you give a path to a
script to add an IP and another path to remove an IP. The scripts
(de)populated some file and would call pf to reload the table. The
following would be the relevant pf rules:
table <denyhosts> persist file "/var/db/denyhosts/pftable"
block in log quick on $EXT_NIC from <denyhosts>
This all would have been well and good until I recently noticed that my
blacklist file was growing at an ever steady rate, and included
duplicates. Basically, DenyHosts kept adding the same IPs, and never
took any out. There were easily thousands of entries.
For a while I thought it was a problem with my scripts, and I debugged
the hell out of it (not easy when the only way to test it is to wait for
someone to brute force your ssh server) and finally realized that it was
some bug in DenyHosts. I probably should have filed a bug, or brought it
to the attention of the developers, but by that time, I was pretty
disgusted with everything, so I just turned it off altogether
A few months ago, someone was asking on the FreeBSD mailing list about
how to secure their server and someone suggested SSHGuard. I don't know
how I didn't find out about this project earlier. It's been around since
2007 at least.
SSHGuard has the following features that I liked:
- parses many types logs, not just ssh
- can talk to pf directly
- has a port (security/sshguard-pf) which works out of the box with
little to no configuration
- written in C, so no dependencies on scripts demanding the interpreter
(other programs seem to eat a lot of resources)
- didn't I mention that the needed configuration is tiny?
Here's what I did to get it working:
- installed the port
- added the following pf rules:
table <sshguard> persist
block in log quick on $EXT_NIC proto tcp from <sshguard> \
to any port 22 label "ssh bruteforce"
- added the following to /etc/rc.conf
sshguard_enable="yes"
sshguard_watch_logs="/var/log/auth.log"
- created the file /usr/local/etc/sshguard.whitelist and put in my
whitelist entries (SSHGuard is really flexible about the format of
this file)
And that was pretty much it.
My one minor gripe is that SSHGuard's blacklist DB file is not easily
parsable, so I'm stuck to dumping the pf table (pfctl -t sshguard -T
show) to look at blacklisted entries. Not a big deal.
And that was it. SSHGuard has worked perfectly for me. I will soon
change the pf rule to block blacklisted IPs access to everything on my
hosts, not just port 22.