To prevent scripts from brute forcing their way into my VPS via SSH I use Fail2ban. It's a tool that checks the logs for password failures and set IP rules that blocks that user's IP for a given time.
I have it already set up to send emails (one of the default actions), but I wanted it to send me a text message every time an IP gets banned.
Fail2ban does not ship with such an action. Fortunately, it's not hard to create one.
How to extend fail2ban with custom actions?
It's easy to extend Fail2ban with custom actions. You only need to do two things:
1. Create a new action in the /etc/fail2/ban/actions.d directory
2. Configure jail.local to use that action
Create new action in actions.d
The easiest way to create a new action is to copy dummy.conf to new-action.conf and edit it. You'll find the different "hooks" you can use to execute your commands. Variables are passed via "<variable>" syntax.
Below you'll find my sms.conf.
#
# Author: Toon Ketels
#
# $Revision$
#
[Definition]
# Option: actionstart
# Notes.: command executed once at the start of Fail2Ban.
# Values: CMD
#
actionstart = /home/all/scripts/fail2ban-sms.sh start
# Option: actionstop
# Notes.: command executed once at the end of Fail2Ban
# Values: CMD
#
actionstop = /home/all/scripts/fail2ban-sms.sh stop
# 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> IP address
# <failures> number of failures
# <time> unix timestamp of the ban time
# Values: CMD
#
actionban = /home/all/scripts/fail2ban-sms.sh ban <ip>
# Option: actionunban
# Notes.: command executed when unbanning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: <ip> IP address
# <failures> number of failures
# <time> unix timestamp of the ban time
# Values: CMD
#
actionunban = /home/all/scripts/fail2ban-sms.sh unban <ip>
[Init]
init = 'Custom startup message
Above you see we don't actually send text messages directly from within this file, but invoke the script located at /home/all/scripts/fail2ban-sms.sh. We use the <ip> variable to be send in the text message and pass it as an argument to the script.
Using scripts makes it easier to change the texting implementation later on (or when we would like to change provider).
Before we look into the text messaging script, let's activate the command.
Config fail.local to execute action
Configure Fail2ban by copying jail.conf to jail.local and edit the file. We want texting whenever someone tries to bruteforce ssh. So we add "sms" to the list of actions in the ssh section like below.
#
# in /etc/fail2ban/jail.local.
#
# Optionally you may override any other parameter (e.g. banaction,
# action, port, logpath, etc) in that section within jail.local
[ssh]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 6
action = mail-whois[name=SSH, dest=my.email@gmail.com]
sms
Texting using twilio
Twilio's API makes it easy to send sms's. Just POST to their api to text. Below you find the script used to perform the request to their API.
#!/bin/bash
# Sends text messages using twilio api
# to alert webmaster of banning.
#
# Requires one argument, one of the following:
# start
# stop
# ban
# unban
#
# Optional second argument: IP for ban/unban
# Include file with the following content:
# sid=<twilio account sid>
# token=<twilio auth token>
# from=<phone number>
# to=<phone number>
source secret.conf
# Display usage information
function show_usage {
echo "Usage: $0 action <ip>"
echo "Where action is start, stop, ban, unban"
echo "and ip is optional passed to ban, unban"
exit
}
# Actually send sms
# Expects the sms content (body) to be passed
# as argument.
function send_sms {
/usr/bin/curl -X POST "https://api.twilio.com/2010-04-01/Accounts/$sid/SMS/Messages.json" -d "From=$from" -d "To=$to" -d "Body=$1" -u "$sid:$token" >> '/home/all/log/fail2ban-sms.log'
exit
}
# Check for script arguments
if [ $# -lt 1 ]
then
show_usage
fi
# Take action depending on argument
if [ "$1" = 'start' ]
then
message='Fail2ban+just+started.'
send_sms $message
elif [ "$1" = 'stop' ]
then
message='Fail2ban+just+stopped.'
send_sms $message
elif [ "$1" = 'ban' ]
then
message=$([ "$2" != '' ] && echo "Fail2ban+just+banned+$2" || echo 'Fail2ban+just+banned+an+ip.' )
send_sms $message
elif [ "$1" = 'unban' ]
then
message=$([ "$2" != '' ] && echo "Fail2ban+just+unbanned+$2" || echo "Fail2ban+just+unbanned+an+ip." )
send_sms $message
else
show_usage
The script expects a secret.conf in the same directory to read the Twilio authentication data and phone numbers from. The output of the requests are appended to a logfile in /home/all/log/fail2ban-sms.log.
Repo
You find the config file and script in github repo.