Did you ever wonder how you can set up Fail2ban on Linux with E-Mail and/or Telegram messenger notification?
Hey, my name is "Tux" and this tutorial will show you how to set up Fail2ban so it can notify you about banning events by E-Mail and/or your personal and specific Telegram messenger channel by using Fail2ban's smtp.py
pre-defined Python script.
Note
Note
$ fail2ban-server -V
$ fail2ban-client -V
In addition, for E-Mail and/or Telegram notifications, it is assumed you've already set up a working E-Mail client and/or the specific smtp-to-telegram docker application. Optionally, to make smtp-to-telegram run on a Synology NAS with Docker package capability, you can also refer to this tutorial.
As you are aware of the information boxes above we move to practice now.
Let's begin!
Calling the Fail2ban's included smtp.py
Python script with the according parameters as an action from your Fail2ban jail-file is really straight forward.
Just for your information: It might be helpful to take a look on the available defined parameters on the Parameters
-section inside the smtp.py
-script (Note that this is just an outtake, the whole script has a lot more content, of course):
Parameters ---------- jail : Jail The jail which the action belongs to. name : str Named assigned to the action. host : str, optional SMTP host, of host:port format. Default host "localhost" and port "25" user : str, optional Username used for authentication with SMTP server. password : str, optional Password used for authentication with SMTP server. sendername : str, optional Name to use for from address in email. Default "Fail2Ban". sender : str, optional Email address to use for from address in email. Default "fail2ban". dest : str, optional Email addresses of intended recipient(s) in comma space ", " delimited format. Default "root". matches : str, optional Type of matches to be included from ban in email. Can be one of "matches", "ipmatches" or "ipjailmatches". Default None (see man jail.conf.5).
As you can see on the script outtake above that there are only two parameters required when executing the smtp.py
-action, all other parameters are optional (Note that the required parameters jail
and name
are being transferred automatically, you don't have to add them when calling the smtp.py
-action. But you can override them if you need to.). But be aware, that those parameters with pre-defined default values actually do(!) send their default value by default when executing the smtp.py
-action!
For example: For Telegram notifications it is just enough to just call the pre-defined smtp.py
-action like this, all other parameters are not necessary to be set (Of course for E-Mail notification with user authentication you would have to set more parameters, in this case just do as your SMTP server requires!):
smtp.py[host="<mySmtpToTelegramHostIPAddress>:<mySmtpToTelegramHostPort>", sender="", dest="foo@bar.com"]
Note that the parameter sender
has to be included with an empty string in case you are configuring smtp-to-telegram notifications because if you leave it unset it takes the default value fail2ban
which did not work in my case (I've had to learn it the hard way!).
The destination
content on the other hand really does not matter when using the smtp-to-telegram service, you can just put in foo@bar.com
like I did, if you like.).
Here is an example of a running and fully working jail.local
-file:
[DEFAULT] ignoreip = 127.0.0.1/8 bantime = 10m findtime = 10m maxretry = 5 banaction = iptables-multiport [sshd] enabled = true backend = systemd filter = sshd action = iptables[name=SSH, port=ssh, protocol=tcp] smtp.py[host="172.16.0.2:2500", sender="", dest="foo@bar.com"] logpath = /var/log/secure bantime = -1 findtime = 300 maxretry = 3
You can see on the jail.local
-content above that there are the folowing two actions being called:
action = iptables[name=SSH, port=ssh, protocol=tcp] smtp.py[host="172.16.0.2:2500", sender="", dest="foo@bar.com"]
Please note: It is important to know that Fail2ban jail-files are not very tolerant when it comes into whitespaces and tabulators. In my case, directly after the first action iptables[name=SSH, port=ssh, protocol=tcp]
, I had to add a page break followed by a single tabulator. Please do not add any whitespaces and don't copy-paste from this website! Type it all down by your own to make sure it is being formatted correctly!
Also note that Fail2ban does take the SSH port-number defined inside the /etc/ssh/sshd_config
-file. So if you have changed the default port number from 22
to whatever number, Fail2ban will take the correct port number so you don't have to worry about that.
Also note that you can repeat the smtp.py
-action as many times as you want in case you want to have multiple notification channels (for example Telegram and E-Mail).
Now, after configuring everything similar as showed above please restart the Fail2ban service:
$ systemctl restart fail2ban
The tutorial should be finished here. Just check it by doing some SSH failure attempts (according to your jail-file configuration) manually to provoke an SSH-ban. You should get notified on your personal Telegram or E-Mail channel.
If not, you have either misconfigured your smtp-to-telegram docker service or -like in my case- you have a Linux system with enabled SELinux service set to enforced
so you will not get any notifications yet as SELinux will prevent the Python script from being executed by default.
In this case, please follow the tutorial below.
After everything has been set up as described above, let's get to the tricky part now. First, edit the following file:
$ vi /etc/selinux/config
Now change the following line
SELINUX=enforcing
to
SELINUX=permissive
After the next system reboot SELinux is will be set to permissive
mode which is required to capture the events preventing the smtp.py
-script from being executed.
So let's now reboot the system:
$ reboot now
After reboot SELinux is now in permissive
mode.
Check this by executing:
$ getenforce
Which should give you the following output:
Permissive
You will note soon that Telegram and/or E-Mail notifications should now work as SELinux is not in blocking mode anymore for now. But you don't want SELinux being disabled permanently as this takes down your system's security! So just keep following the tutorial!
Login again with user root
via SSH.
Now make sure to provoke a few Fail2ban SSH-bans so the smtp.py-script blocking events will be captured by SELinux logs.
After that (as already mentioned at least you now should have got new Telegram and/or E-Mail notifications), check the logs if it got blocked some smtp.py
-script dependencies:
$ cat /var/log/audit/audit.log | grep fail2ban_t
If you see something like…
type=AVC msg=audit(1598509657.351:59): avc: denied { search } for pid=1175 comm="f2b/server" name="__pycache__" dev="dm-0" ino=12590952 scontext=system_u:system_r:fail2ban_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass=dir permissive=1 type=AVC msg=audit(1598509657.351:59): avc: denied { read } for pid=1175 comm="f2b/server" name="smtp.cpython-36.pyc" dev="dm-0" ino=12590953 scontext=system_u:system_r:fail2ban_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass=file permissive=1 type=AVC msg=audit(1598509657.351:59): avc: denied { open } for pid=1175 comm="f2b/server" path="/etc/fail2ban/action.d/__pycache__/smtp.cpython-36.pyc" dev="dm-0" ino=12590953 scontext=system_u:system_r:fail2ban_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass=file permissive=1 type=AVC msg=audit(1598509657.353:60): avc: denied { getattr } for pid=1175 comm="f2b/server" path="/etc/fail2ban/action.d/__pycache__/smtp.cpython-36.pyc" dev="dm-0" ino=12590953 scontext=system_u:system_r:fail2ban_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass=file permissive=1 type=AVC msg=audit(1598509657.873:61): avc: denied { name_connect } for pid=1175 comm="f2b/a.sshd" dest=2500 scontext=system_u:system_r:fail2ban_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket permissive=1 type=AVC msg=audit(1598509705.324:115): avc: denied { name_connect } for pid=1175 comm="f2b/a.sshd" dest=2500 scontext=system_u:system_r:fail2ban_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket permissive=1 type=AVC msg=audit(1598509705.998:120): avc: denied { search } for pid=1652 comm="f2b/server" name="__pycache__" dev="dm-0" ino=12590952 scontext=system_u:system_r:fail2ban_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass=dir permissive=1 type=AVC msg=audit(1598509705.998:120): avc: denied { read } for pid=1652 comm="f2b/server" name="smtp.cpython-36.pyc" dev="dm-0" ino=12590953 scontext=system_u:system_r:fail2ban_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass=file permissive=1 type=AVC msg=audit(1598509705.998:120): avc: denied { open } for pid=1652 comm="f2b/server" path="/etc/fail2ban/action.d/__pycache__/smtp.cpython-36.pyc" dev="dm-0" ino=12590953 scontext=system_u:system_r:fail2ban_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass=file permissive=1 type=AVC msg=audit(1598509705.998:121): avc: denied { getattr } for pid=1652 comm="f2b/server" path="/etc/fail2ban/action.d/__pycache__/smtp.cpython-36.pyc" dev="dm-0" ino=12590953 scontext=system_u:system_r:fail2ban_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass=file permissive=1 type=AVC msg=audit(1598509706.147:122): avc: denied { name_connect } for pid=1652 comm="f2b/a.sshd" dest=2500 scontext=system_u:system_r:fail2ban_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket permissive=1
…it is clear that SELinux is preventing the smtp.py
-script from being executed successfully.
If so, let's create our own SELinux policy package.
First, let's create the following directory:
$ mkdir /root/selinux
Navigate into it:
$ cd /root/selinux
Now let's create our own SELinux policy package inside the current directory:
$ grep "fail2ban_t" /var/log/audit/audit.log | audit2allow -M fail2ban-smtp-py
Now let's load/activate the custom SELinux module:
$ semodule -i /root/selinux/fail2ban-smtp-py.pp
Finally turn SELinux back to enforcing
mode:
$ vi /etc/selinux/config
Chage the following line
SELINUX=permissive
to
SELINUX=enforcing
Now reboot the system:
$ reboot now
After reboot SELinux is now set back to enforcing
mode.
Check this by executing:
$ getenforce
Which should give you the following output:
Enforcing
Telegram and/or E-Mail notification should work now.
Note that you can always unload/disable the custom SELinux module by executing:
$ semodule -r fail2ban-smtp-py