How to use PAM to limit failed login attempts by IP?

I'm working through a process of hardening my server security against the daily hacking attempts that arise the moment you attach a server to an IP and give it a domain name. I get anywhere from 1 to 8 brute force attempts daily to access SSH as either root or just brute force trying different names and this is on a server with no public reputation (its not running any big websites etc). Because of the way I have my SSH server configured I'm pretty sure these attempts will also fail, but I really dont like letting people try.

I have of course also set up connection rate limiting for the more sensitive services including SSH.

What I'm doing at the moment:

I can see from my auth.log that PAM does get the remote IP address of those trying to login and I'm currently using a script which periodically scans for these failed attempts and adds an IP block the fire wall.

What I'd like to do:

What I want to do is make this IP banning process much quicker to respond. That is rather than waiting for the polling script to pick it up, I want a PAM module to count successive failed attempts from an IP (not a service or user) and take some action either such as:

  • refuse all future login attempts from that IP
  • fire a command which will add a rule to the firewall to ban the IP completely

The Question:

Is there already a good PAM module which can take note of the IPs failing authentication or do I need to write my own?


What I recommend is to stagger your security solutions. Security is best implemented in Layers, and having one solutions means you will have a Single Point of Failure.

Fail2Ban, as stated above by Jeff Ferland, is a good first step solution. It will monitor your log files for signs of a brute force attack, and can be configured to listen generally against PAM.

But what happens if this log file is lost? permissions change? if the log file destination changes? if fail2ban crashed? if an update changes the way you intend things to work? the regex pattern must be updated? what happens if the log file destination drive or partition becomes full? fail2ban becomes useless.


  • Introducing libpam_shield

There is a PAM Module called pam_shield. this is not only more efficient (operating directly within the Login layer), it uses a fast access database, which can persist across reboots.

it uses less memory, and does not require a running service which can fail. pam_shield can also be configured to work with your routing table, as well as IPTables.

Much like Fail2Ban, you give it a period of time to consider the host for a ban. you supply the maximum attempts the remote host can make, and the period of time which to ban them for.

To make it work nicely with Fail2Ban, set these to 1.5 times that of what is configured in Fail2Ban. you might also make the Ban period much longer. this way, fail2ban will ban the user the first time around... and if their ban expires, and they are caught again, it will ban them for much longer the second time around.

Here is a link to the configuration files manual page: shield.conf


  • Introducing pam_tally2

You might also consider pam_tally2 for locking a specific users account.

if a user account is being specifically targeted, you would need to lock out this user account, and prevent login all-together, or until the attack is dealt with.

this is useful especially on a shared server, when the attack is originating from "the inside". when you can’t block the local host (i.e. 127.0.0.1).

Hopefully this helps! I realize the original post is a bit old now, but It's very important to implement security in layers... and to cover all your bases! there is NO package you can "just install" to make your system secure. not even Fail2Ban.


There is a PAM module that lets you maintain a blacklist, called PAM Auto Blacklist (pam_abl). Until recently it hadn't been updated in a while, but it has a new maintainer who has been actively working on it again.

The module has always done the first step in what you would like to do, that is it will ban future login attempts from an IP that has failed and been banned. Those attempts make it through the firewall and back up to PAM again though.

Though there is still not a built in way to interact with the firewall from module itself, it can now run arbitrary commands which allows for the second step also.

I run a command to add a banned host into an ipset that I have setup in my firewall.


This is how I handle banning from PAM to the firewall:

In /etc/pam.d/sshd:

auth       include      system-remote-login
auth       required     pam_abl.so config=/etc/security/pam_abl.conf

In the pam_abl.conf file:

host_clr_cmd=ipset del blacklist %h; logger clear host %h
host_blk_cmd=ipset add blacklist %h; logger block host %h

That with immediately add a host that fails the criteria to be blocked added to an ipset list that I have blocked in iptables. You could also directly drop the host in iptables like this:

host_blk_cmd=iptables --append INPUT --source %h --jump DROP; logger block host %h

There are more configuration options and the setup for the firewall, but that is the part that keeps banned IP's from coming through the firewall again.