Précédemment, nous avons vu Fail2ban configuré pour Dovecot et Postfix, mais l’inconvénient de la solution proposée dans une architecture de serveurs derrière un routeur, c’est que pour le coup, chaque serveur aura ses propres règles de blocage.
J’aimerais bien centraliser tout. Si un boulet se présente sur le serveur mail, autant le bloquer sur tout et ce, dès son arrivée sur mon routeur…
Du coup, il faut trouver le moyen de faire le blocage directement dans le firewall de ce dernier. Quid ?
Installer fail2ban sur le routeur ? Pourquoi pas, mais il lui faudrait donc la possibilité de lire les logs des autres VMS…
Des partages NFS ? Non…
Rapatrier les logs sur le routeur pour que fail2ban fasse son taf ? Bof, mon routeur n’a pas pour vocation de centraliser les logs…
Hum… Fail2ban sur le routeur n’est pas la solution.
Le truc serait de garder fail2ban sur chaque machine avec ses logs et sa config et de piloter le firewall du routeur…
En voila une bonne idée !
Pour cela, on va passer par un truc que j’affectionne, un petit système client-serveur en python. C’est rapide à mettre en place et ça répond parfaitement à mon problème.
Sur le routeur, un serveur en écoute des instructions des clients pour modifier le firewall. Et sur chaque serveur, un client actionné par fail2ban pour balancer l’ordre.
Simple non ?
II – Sur le routeur
A – De nouvelles chaines
Sur le firewall, on va déjà préparer le terrain et créant des chaines spécifiques.
Je pars du principe que vous utilisez un fichier pour les règles du firewall. On va dire qu’il s’appelle firewall.sh.
Donc, dans firewall.sh, après :
#!/bin/bash iptables -t filter -F iptables -t filter -X iptables -t nat -F iptables -t nat -X iptables -t mangle -F iptables -t mangle -X
Ajoutez :
# creation des chaines iptables -N f2b-postfix iptables -N f2b-dovecot # on ajoute un retour dans ces chaines (pour revenir à INPUT ou FORWARD, selon le cas) iptables -A f2b-postfix -j RETURN iptables -A f2b-dovecot -j RETURN # Puis on indique dans INPUT et FORWARD de traverser les nouvelles chaines. iptables -I INPUT -j f2b-postfix iptables -I INPUT -j f2b-dovevot iptables -I FORWARD -j f2b-postfix iptables -I FORWARD -j f2b-dovecot [...]
On reprend le concept qu’utilise Fail2ban par défaut, à savoir créer une nouvelle chaine, puis faire passer les flux dedans. Si rien ne bloque, ça revient dans les chaines INPUT ou FORWARD (en fonction) et passe les autres règles.
Et j’en profite pour créer une chaine par service, histoire de bien voir par la suite quel service à fait le blocage.
Au passage pensez à autoriser en INPUT sur le port que vous choisirez pour votre serveur.
iptables -t filter -A INPUT -p tcp -s 10.20.1.0/24 --dport 666 -j ACCEPT
Mon réseau interne entre les vms étant en 10.20.1.0/24
Une fois votre fichier firewall.sh ou autre modifié, on exécute :
routeur# ./firewall.sh
B – Serveur Python
Maintenant, on va créer le serveur python qui va écouter les ordres des autres VMS, et appliquer les règles.
On installe python :
routeur# apt-get install python
Puis dans un fichier : /srv/pyban.py, vous copiez cela :
#!/usr/bin/env python import socket import os import threading class ClientThread(threading.Thread): def __init__(self, ip, port, clientsocket): threading.Thread.__init__(self) self.ip = ip self.port = port self.clientsocket = clientsocket def run(self): r = self.clientsocket.recv(1024) item = r.split(":") if item[0] == "ban": chain = "iptables -I "+item[2]+" -s "+item[1]+" -j DROP" os.system(chain) if item[0] == "unban": chain = "iptables -D "+item[2]+" -s "+item[1]+" -j DROP" os.system(chain) else: error = 1 tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) tcpsock.bind(("XXX.XXX.XXX.XXX",666)) while True: tcpsock.listen(5) (clientsocket, (ip, port)) = tcpsock.accept() newthread = ClientThread(ip, port, clientsocket) newthread.start() tcpsock.close()
Tout simple, on a un serveur qui écoute sur le port 666, avec la gestion du multithread, ca ne coute rien.
Il attend comme paramètres ce qu’il faut faire (ban ou unban), l’ip et la chaine dans laquelle on se place.
Pensez bien sur à remplacer XXX.XXX.XXX.XXX par l’ip interne du routeur (par exemple, 10.20.1.1; pas de localhost car sinon, les clients ne pourraient le joindre…)
On peut déjà tester si cela tourne sans erreur :
# python /srv/pyban.py
Ctrl+C pour arrêter.
C – Service
Maintenant, on va en faire un service, histoire qu’il se lance tout seul et soit autonome.
Créez un fichier /etc/systemd/system/pyban.service et mettez y :
Description=Server Python Ban After=network-online.target [Service] Type=idle ExecStart=/usr/bin/python /srv/pyban.py [Install] WantedBy=multi-user.target
Puis on l’active et on le démarre :
# systemctl enable pyban.service # systemctl start pyban.service
Voila pour le routeur.
II – Sur le serveur
Pour l’exemple, je reprend mon serveur de mail.
A – Client python
Bien évidement, on installe python :
mail# apt-get install python
On va créer ensuite un fichier /srv/pybanclient.py avec dedans :
#!/usr/bin/env python import socket import sys try: s = ":"; seq = (sys.argv[1], sys.argv[2], sys.argv[3]); sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(("XXX.XXX.XXX.XXX", 666)) sock.send(s.join(seq)) sock.close except(socket.error): sys.exit()
Bien évidement, XXX.XXX.XXX.XXX doit être remplacé par l’ip du routeur.
B – Fail2ban
1 – Action
On va créer un fichier action nommé /etc/fail2ban/action.d/pyban.conf avec ce qui suit dedans :
[Definition] actionban = python /srv/pybanclient.py ban <ip> <name> actionunban = python /srv/pybanclient.py unban <ip> <name>
2 – Jail
On va modifier nos deux jails.
Tout d’abord /etc/fail2ban/jail.d/postfix.conf :
[postfix-sasl] enabled = true filter = postfix-sasl action = pyban[name=f2b-postfix] mail[name=Postfix SASL] bantime = 3600 maxretry = 2 logpath = /var/log/mail.log
Puis /etc/fail2ban/jail.d/dovecot.conf :
[dovecot] enabled = true filter = dovecot action = pyban[name=f2b-dovecot] mail[name=Dovecot] bantime = 3600 maxretry = 2 logpath = /var/log/mail.log
Et on termine en rechargeant :
mail# service fail2ban reload
III – Test
Rien de plus simple.
Sur le serveur :
serveur# fail2ban-client set postfix-sasl banip XXX.XXX.XXX.XXX
Sur le routeur :
routeur# iptables -L -n
On doit voir l’ip apparaitre dans la bonne chaine avec un DROP devant .
Et si on déban sur le serveur :
serveur# fail2ban-client set postfix-sasl unbanip XXX.XXX.XXX.XXX
Ce doit être nettoyé sur le routeur :
routeur# iptables -L -n
iV – Conclusion
Bah voila, on a enfin notre fail2ban qui peut piloter un FW en amont afin de voir les boulets bloqués sur tous nos services. Rien de bien sorcier au final…
Par la suite, on pourra rajouter d’autres services en pilotage en rajoutant leurs règles dans le FW du routeur et avec des clients python sur les serveurs.