Protéger son serveur avec fail2ban

fail2ban 12 oct. 2023

Tout le monde le sait, un serveur est constamment soumis à des attaques de pirates.

Une bonne solution pour pallier à cela est d'utiliser un parefeu.

fail2ban est justement prévu pour scanner différents logs stockés sur votre serveur et, en fonction de règles préétablies, rejeter les IP qui tentent de vous attaquer.

Commençons donc par l'installer :

dnf -y install fail2ban

Les fichiers de configuration se trouvent dans /etc/fail2ban/ .

Dans ce dossier, vous trouverez un fichier jail.conf qui contient la configuration principale.

Ne le modifiez pas directement mais créez un fichier jail.local .

Pour fail2ban, les fichiers .local ont la priorité sur les .conf, ce qui permet d'éditer les premiers en ayant toujours une sauvegarde de l'original si besoin.

Éditez ce fichier jail.local en y collant les lignes suivantes :

# WARNING: heavily refactored in 0.9.0 release.  Please review and
#          customize settings for your setup.
# Changes:  in most of the cases you should not modify this
#           file, but provide customizations in jail.local file,
#           or separate .conf files under jail.d/ directory, e.g.:
# It will probably be overwritten or improved in a distribution update.
# Provide customizations in a jail.local file or a jail.d/customisation.local.
# For example to change the default bantime for all jails and to enable the
# ssh-iptables jail the following (uncommented) would appear in the .local file.
# See man 5 jail.conf for details.
# bantime = 1h
# [sshd]
# enabled = true
# See jail.conf(5) man page for more information

# Comments: use '#' for comment lines and ';' (following a space) for inline comments


#before = paths-distro.conf
before = paths-fedora.conf

# The DEFAULT allows a global definition of the options. They can be overridden
# in each jail afterwards.



# "bantime.increment" allows to use database for searching of previously banned ip's to increase a 
# default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32...
#bantime.increment = true

# "bantime.rndtime" is the max number of seconds using for mixing with random time 
# to prevent "clever" botnets calculate exact time IP can be unbanned again:
#bantime.rndtime = 

# "bantime.maxtime" is the max number of seconds using the ban time can reach (doesn't grow further)
#bantime.maxtime = 

# "bantime.factor" is a coefficient to calculate exponent growing of the formula or common multiplier,
# default value of factor is 1 and with default value of formula, the ban time 
# grows by 1, 2, 4, 8, 16 ...
#bantime.factor = 1

# "bantime.formula" used by default to calculate next value of ban time, default value below,
# the same ban time growing will be reached by multipliers 1, 2, 4, 8, 16, 32...
#bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor
# more aggressive example of formula has the same values only for factor "2.0 / 2.885385" :
#bantime.formula = ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)

# "bantime.multipliers" used to calculate next value of ban time instead of formula, corresponding
# previously ban count and given "bantime.factor" (for multipliers default is 1);
# following example grows ban time by 1, 2, 4, 8, 16 ... and if last ban count greater as multipliers count, 
# always used last multiplier (64 in example), for factor '1' and original ban time 600 - 10.6 hours
#bantime.multipliers = 1 2 4 8 16 32 64
# following example can be used for small initial ban time (bantime=60) - it grows more aggressive at begin,
# for bantime=60 the multipliers are minutes and equal: 1 min, 5 min, 30 min, 1 hour, 5 hour, 12 hour, 1 day, 2 day
#bantime.multipliers = 1 5 30 60 300 720 1440 2880

# "bantime.overalljails" (if true) specifies the search of IP in the database will be executed 
# cross over all jails, if false (default), only current jail of the ban IP will be searched
#bantime.overalljails = false

# --------------------

# "ignoreself" specifies whether the local resp. own IP addresses should be ignored
# (default is true). Fail2ban will not ban a host which matches such addresses.
#ignoreself = true

# "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban
# will not ban a host which matches an address in this list. Several addresses
# can be defined using space (and/or comma) separator.
ignoreip = ::1

# External command that will take an tagged arguments to ignore, e.g. <ip>,
# and return true if the IP is to be ignored. False otherwise.
# ignorecommand = /path/to/command <ip>
ignorecommand =

# "bantime" is the number of seconds that a host is banned.
bantime = 7d

# A host is banned if it has generated "maxretry" during the last "findtime"
# seconds.
findtime = 10m

# "maxretry" is the number of failures before a host get banned.
maxretry = 3

# "maxmatches" is the number of matches stored in ticket (resolvable via tag <matches> in actions).
maxmatches = %(maxretry)s

# "backend" specifies the backend used to get files modification.
# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto".
# This option can be overridden in each jail as well.
# pyinotify: requires pyinotify (a file alteration monitor) to be installed.
#              If pyinotify is not installed, Fail2ban will use auto.
# gamin:     requires Gamin (a file alteration monitor) to be installed.
#              If Gamin is not installed, Fail2ban will use auto.
# polling:   uses a polling algorithm which does not require external libraries.
# systemd:   uses systemd python library to access the systemd journal.
#              Specifying "logpath" is not valid for this backend.
#              See "journalmatch" in the jails associated filter config
# auto:      will try to use the following backends, in order:
#              pyinotify, gamin, polling.
# Note: if systemd backend is chosen as the default but you enable a jail
#       for which logs are present only in its own log files, specify some other
#       backend for that jail (e.g. polling) and provide empty value for
#       journalmatch. See
backend = auto

# "usedns" specifies if jails should trust hostnames in logs,
#   warn when DNS lookups are performed, or ignore all hostnames in logs
# yes:   if a hostname is encountered, a DNS lookup will be performed.
# warn:  if a hostname is encountered, a DNS lookup will be performed,
#        but it will be logged as a warning.
# no:    if a hostname is encountered, will not be used for banning,
#        but it will be logged as info.
# raw:   use raw value (no hostname), allow use it for no-host filters/actions (example user)
usedns = warn

# "logencoding" specifies the encoding of the log files handled by the jail
#   This is used to decode the lines from the log file.
#   Typical examples:  "ascii", "utf-8"
#   auto:   will use the system locale setting
logencoding = auto

# "enabled" enables the jails.
#  By default all jails are disabled, and it should stay this way.
#  Enable only relevant to your setup jails in your .local or jail.d/*.conf
# true:  jail will be enabled and log files will get monitored for changes
# false: jail is not enabled
enabled = false

# "mode" defines the mode of the filter (see corresponding filter implementation for more info).
mode = normal

# "filter" defines the filter to use by the jail.
#  By default jails have names matching their filter name
filter = %(__name__)s[mode=%(mode)s]


# Some options used for actions

# Destination email address used solely for the interpolations in
# jail.{conf,local,d/*} configuration files.
destemail = root

# Sender email address used solely for some actions
sender = root

# E-mail action. Since 0.8.1 Fail2Ban uses sendmail MTA for the
# mailing. Change mta configuration parameter to mail if you want to
# revert to conventional 'mail'.
mta = mail

# Default protocol
protocol = tcp

# Specify chain where jumps would need to be added in ban-actions expecting parameter chain
chain = <known/chain>

# Ports to be banned
# Usually should be overridden in a particular jail
port = 0:65535

# Format of user-agent
fail2ban_agent = Fail2Ban/%(fail2ban_version)s

# Action shortcuts. To be used to define action parameter

# Default banning action (e.g. iptables, iptables-new,
# iptables-multiport, shorewall, etc) It is used to define
# action_* variables. Can be overridden globally or per
# section within jail.local file
banaction = iptables-multiport
banaction_allports = iptables-allports

# The simplest action to take: ban only
action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]

# ban & send an e-mail with whois report to the destemail.
action_mw = %(action_)s
            %(mta)s-whois[sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]

# ban & send an e-mail with whois report and relevant log lines
# to the destemail.
action_mwl = %(action_)s
             %(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]

# See the IMPORTANT note in action.d/xarf-login-attack for when to use this action
# ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines
# to the destemail.
action_xarf = %(action_)s
             xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath="%(logpath)s", port="%(port)s"]

# ban & send a notification to one or more of the 50+ services supported by Apprise.
# See for details on what is supported.
# You may optionally over-ride the default configuration line (containing the Apprise URLs)
# by using 'apprise[config="/alternate/path/to/apprise.cfg"]' otherwise
# /etc/fail2ban/apprise.conf is sourced for your supported notification configuration.
# action = %(action_)s
#          apprise

# ban IP on CloudFlare & send an e-mail with whois report and relevant log lines
# to the destemail.
action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"]
                %(mta)s-whois-lines[sender="%(sender)s", dest="%(destemail)s", logpath="%(logpath)s", chain="%(chain)s"]

# Report block via fail2ban reporting service API
# See the IMPORTANT note in action.d/blocklist_de.conf for when to use this action.
# Specify expected parameters in file action.d/blocklist_de.local or if the interpolation
# `action_blocklist_de` used for the action, set value of `blocklist_de_apikey`
# in your `jail.local` globally (section [DEFAULT]) or per specific jail section (resp. in 
# corresponding jail.d/my-jail.local file).
action_blocklist_de  = blocklist_de[email="%(sender)s", service="%(__name__)s", apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"]

# Report ban via
# See action.d/abuseipdb.conf for usage example and details.
action_abuseipdb = abuseipdb

# Choose default action.  To change, just override value of 'action' with the
# interpolation to the chosen action shortcut (e.g.  action_mw, action_mwl, etc) in jail.local
# globally (section [DEFAULT]) or per specific section
action = %(action_)s

Les lignes les plus importantes sont :
- ignoreip : vous pouvez rajouter des IP qui seront mises en liste blanche, elles peuvent être en IPv4 ou IPv6 et doivent être séparées par des espaces
- bantime : le temps où l'IP en question sera bannie, ici 7d, donc 7 jours
- findtime : l'intervalle de temps où plusieurs tentatives d'attaques consécutives vont déclencher la règle
- maxretry : le nombre maximum de fois pendant le findtime où telle IP peut déclencher une règle sans se faire bannir

Viennent ensuite se rajouter les règles, toujours dans le fichier jail.local, à la suite de la configuration précédente :

# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode   = normal
enabled  = true
port     = 1982
logpath  = /var/log/secure
backend  = %(sshd_backend)s
mode     = aggressive
maxretry = 1
bantime  = 7d
action   = iptables-multiport[name="sshd", port="ssh"]

Le nom du filtre est précisé au début, entre crochets, et doit correspondre au fichier du même nom qui se trouve dans le dossier /etc/fail2ban/filter.d/, par exemple ici pour la règle [sshd] le fichier sera /etc/fail2ban/filter.d/sshd.conf .

Un autre exemple de règle plus classique, qui va scanner les fichiers log d'Apache et bannir les bots malveillants :

# Ban hosts which agent identifies spammer robots crawling the web
# for email addresses. The mail outputs are buffered.
enabled  = true
port     = http,https
logpath  = /var/log/httpd/*_log
maxretry = 1
bantime  = 7d
action   = iptables-multiport[name="apache-badbots", port="http,https"]

enabled  = true
port     = http,https
logpath  = /var/log/httpd/*_log
maxretry = 1
bantime  = 7d
action   = iptables-multiport[name="apache-botsearch", port="http,https"]

Information complémentaire sur les actions, ici iptables-multiport, elles correspondent aux fichiers du même nom se trouvant dans le dossier /etc/fail2ban/action.d/ .

Je vous rajoute ici un filtre plutôt important, pour se prémunir de la faille log4j, le fichier à créer étant /etc/fail2ban/filter.d/log4j-jndi.conf :

failregex = (?i)^<HOST> .* ".*\$.*(7B|\{).*(lower:)?.*j.*n.*d.*i.*:.*".*?$

Rajoutez ensuite ces lignes à la fin du fichier /etc/fail2ban/jail.local :

enabled  = true
port     = http,https
logpath  = /var/log/httpd/*_log
maxretry = 1
bantime  = 7d
action   = iptables-multiport[name="log4j-jndi", port="http,https"]

Note importante concernant les règles : il faut absolument que le ou les fichiers précisés à la ligne logpath existent, sinon fail2ban ne pourra pas démarrer.

Une fois les règles voulues en place, vous pouvez démarrer fail2ban et l'exécuter au démarrage du serveur :

systemctl enable fail2ban && systemctl start fail2ban

Il existe également un utilitaire intégré appelé fail2ban-client pour vérifier le statut et effectuer d'autres actions :

# Vérifier le statut de fail2ban et le nombre de règles
fail2ban-client status

# Vérifier le statut d'une règle en particulier ainsi que le nombre d'IP bannies pour celle-ci
fail2ban-client status nom_de_la_règle

# Supprimer une IP d'un ban
fail2ban-client set nom_de_la_règle unbanip ip_bloquée

# Supprimer toutes les IP des bans
fail2ban-client unban --all

Dernier point, n'oubliez pas de recharger fail2ban si vous modifiez un des fichiers de configuration :

systemctl reload fail2ban

Mots clés


Passionné par le web et les serveurs, je vous fais découvrir toutes sortes de news, de tutos, de scripts et autres points relatifs à cet univers sans limite !