Configuration Logstash - Fail2ban

De EjnTricks

Fail2ban est un outil très pratique pour interdire l'accès à des machines en fonction des tentatives d'accès et l'analyse des traces, sur serveur Web ou en SSH par exemple.

Cet article présente la mise ne place d'une configuration pour Logstash afin de parcourir les fichiers traces de Fail2ban et de stocker les informations des actions de bannissement dans Elasticsearch. Ainsi, il est possible de construire des tableaux de bords pour visualiser l'activité.


Warning-icon.png Attention, la configuration mise en place n'utilise pas un index "standard" de Logstash. Donc, certains champs sont mals configurés et difficilement exploitables. Par exemple les informations de geolocalisation ne pourront pas être exploitées sur une visualisation avec une carte dans Kibana. Des articles sont en cours de préparation pour la configuration des indexes et des mappings.


Hand-icon.png Votre avis

Nobody voted on this yet

 You need to enable JavaScript to vote


Study icon.png Pré requis

Le compte d'exécution de Logstash, soit logstash dans le cadre de cette installation, doit accéder aux fichiers trace de Fail2ban, se trouvant à l'emplacement /var/log/fail2ban.log. Seule la lecture est nécessaire sur ces fichiers.

User-group-icon.png Groupe

Le nouveau groupe loganalyzer est créé afin de faciliter la gestion des droits d'accès.

#sudo groupadd --system loganalyzer

User-icon.png Utilisateurs

Par défaut, les droits d'accès aux fichiers trace de fail2ban sont accordés au groupe adm. Il est donc recommandé d'injecter les utilisateurs de celui-ci dans le nouveau groupe loganalyzer et de le compléter avec le compte d'exécution de Logstash, soit logstash dans le cadre de cette installation.

#sudo usermod -a -G loganalyzer syslog
#sudo usermod -a -G loganalyzer logstash

Icon ACL.png Sécurisation log

Une configuration Logrotate est disponible pour Fail2ban au niveau du fichier /etc/logrotate.d/fail2ban, où sont configurés les droits d'accès pour le fichier trace.

Il faut le modifier afin d'utiliser le nouveau groupe. Le contenu du fichier est alors le suivant.

/var/log/fail2ban.log {

    weekly
    rotate 4
    compress

    delaycompress
    missingok
    postrotate
        fail2ban-client flushlogs 1>/dev/null
    endscript

    # If fail2ban runs as non-root it still needs to have write access
    # to logfiles.
    create 640 root loganalyzer
}

La mise en place des permissions s'effectuant lors de la rotation, il peut être nécessaire de modifier les permissions pour les fichiers déjà existants.

#sudo chown -R root:loganalyzer /var/log/fail2ban*


Icon-Configuration-Settings.png Configuration

Warning-icon.png Attention, la configuration doit être adaptée en fonction des version de Fail2ban installée. En effet, le contenu des fichiers traces peut varier.

Study icon.png Analyse

Dans le cadre de cet article, les messages sont de la forme suivantes.

2018-04-30 11:03:37,826 fail2ban.actions        [1027]: NOTICE  [sshd-invalid-user] Unban 121.18.238.115
2018-04-30 11:07:19,742 fail2ban.filter         [1027]: INFO    [sshd] Found 221.194.47.243
2018-04-30 11:07:21,788 fail2ban.filter         [1027]: INFO    [sshd-invalid-user] Found 221.194.47.243
2018-04-30 11:07:21,792 fail2ban.filter         [1027]: INFO    [sshd] Found 221.194.47.243
2018-04-30 11:07:22,326 fail2ban.actions        [1027]: NOTICE  [sshd-invalid-user] Ban 221.194.47.243
2018-04-30 11:09:01,942 fail2ban.filter         [1027]: INFO    [sshd] Found 221.194.47.243
2018-04-30 11:09:01,944 fail2ban.filter         [1027]: INFO    [sshd-invalid-user] Found 221.194.47.243
2018-04-30 11:09:02,704 fail2ban.actions        [1027]: NOTICE  [sshd-invalid-user] 221.194.47.243 already banned
2018-04-30 11:13:25,987 fail2ban.filter         [1027]: INFO    [sshd] Found 85.29.138.107
2018-04-30 11:13:25,990 fail2ban.filter         [1027]: INFO    [sshd-invalid-user] Found 85.29.138.107
2018-04-30 11:13:26,033 fail2ban.actions        [1027]: NOTICE  [sshd-invalid-user] Ban 85.29.138.107
2018-04-30 11:13:26,056 fail2ban.filter         [1027]: INFO    [sshd] Found 85.29.138.107
2018-04-30 11:13:28,293 fail2ban.filter         [1027]: INFO    [sshd-invalid-user] Found 85.29.138.107
2018-04-30 11:13:28,295 fail2ban.filter         [1027]: INFO    [sshd] Found 85.29.138.107
2018-04-30 11:13:29,270 fail2ban.actions        [1027]: NOTICE  [sshd-invalid-user] 85.29.138.107 already banned

L'objectif est d'extraire l'adresse IP, le nom du filtre (sshd / sshd-invalid-user) ainsi que "l'action", Found / Ban / Unban.

Folder-icon.png Emplacement

La configuration sera placée dans le répertoire conf.d, dont l'emplacement a été externalisé durant l'installation.

#sudo touch /var/opt/logstash/common/conf.d/fail2ban.conf
#sudo chown logstash:logstash /var/opt/logstash/common/conf.d/fail2ban.conf
#sudo chmod 600 /var/opt/logstash/common/conf.d/fail2ban.conf

Process-icon.png Paramétrage

La section input doit référencer l'emplacement du fichier trace.

input {
  file {
    path => "/var/log/fail2ban.log"
    type => "fail2ban"
  }
}

La section output doit référencer l'instance Elasticsearch dans laquelle les données seront injectées. Les instances Logstash et Elasticsearch étant sur la même machine, le nom de la machine est spécifiée avec localhost:9200

output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "fail2ban-%{+YYYY.MM}"
  }
}

A noter le nom de l'index mis en place. Celcui contient la variable %{+YYYY.MM} qi va permettre de mettre en place un indexe par mois.

Enfin la section filter, la plus compliquée, permet de configurer la lecture des fichiers traces. Dans le cadre de cette installation, le contenu est le suivant.

filter {
  if [type] == "fail2ban" {
    grok {
      match => [ "message", "%{TIMESTAMP_ISO8601:bantime} %{PROG}%{SPACE}(\[%{POSINT}\])?: %{WORD}%{SPACE}\[%{GREEDYDATA:jail}\] %{WORD:action} %{IPV4:clientip}" ]
      add_tag => [ "%{action}" ]
      named_captures_only => true
    }

    if "_grokparsefailure" in [tags] {
      drop { }
    }

    date {
      match => [ "bantime", "ISO8601" ]
      target => "bantime"
    }

    geoip {
      source => "clientip"
    }
  }
}

Le filtre sur le type n'est pas forcément nécessaire, car une seule valeur n'est configuré dans le fichier. L'expression régulière dans la section grok utiliser de nombreuse fonctions disponibles en standard.

  • %{TIMESTAMP_ISO8601:bantime} permet d'extraire l'heure de la trace et de stocker la valeur dans le champ bantime;
  • %{PROG} permet de référencer le nom du programme. L'objectif est juste à titre informatif, car aucun nom de champs n'est explicitement spécifié;
  • %{GREEDYDATA:jail} permet d'extraire le nom du bannissement et de stocker la valeur dans le champ jail;
  • %{WORD:action} permet d'extraire l'action et de stocker la valeur dans le champ action;
  • %{IPV4:clientip} permet d'extraire l'adresse IP et de stocker la valeur dans le champ clientip.

Les autres champs sont configurés pour essayer de rendre lisible l'expression.

A noter que la valeur du champ action est également utilisé pour compléter les tag à l'aide de l'instruction add_tag => [ "%{action}" ]. L'instruction named_captures_only => true permet de n'enregistrer que les camps qui sont explicitement nommés, soit les suivants pour cette configuration.

  • bantime;
  • jail;
  • action;
  • clientip.

La section date permet de spécifier les champs de type date, ainsi que le format, soit bantime dans cette configuration.

De la même façon, la section geoip permet de compléter les données à l'aide du plugin Ingest-GeoIP à partir du champs clientip qui contient l'adresse IP.

La dernière section mutate permet de supprimer la valeur potentielle _grokparsefailure dans les données. Mais cela pourrait être supprimé, car les données sont supprimées si la valeur est mise dans les tags.

Le contenu complet du fichier est le suivant.

input {
  file {
    path => "/var/log/fail2ban.log"
    type => "fail2ban"
    # start_position => "beginning"
  }
}

filter {
  if [type] == "fail2ban" {
    grok {
      match => [ "message", "%{TIMESTAMP_ISO8601:bantime} %{PROG}%{SPACE}(\[%{POSINT}\])?: %{WORD}%{SPACE}\[%{GREEDYDATA:jail}\] %{WORD:action} %{IPV4:clientip}" ]
      add_tag => [ "%{action}" ]
      named_captures_only => true
    }

    if "_grokparsefailure" in [tags] {
      drop { }
    }

    date {
      match => [ "bantime", "ISO8601" ]
      target => "bantime"
    }

    geoip {
      source => "clientip"
    }
  }
}

output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "fail2ban-%{+YYYY.MM}"
  }
}


Viewer icon.png Voir aussi

La mise en place de cette configuration s'est inspirée de différentes publications sur Internet. https://blog.projectnine.com/fail2ban-with-elk/

https://miteshshah.github.io/linux/elk/how-to-monitor-fail2ban-logs-on-elk-stack/

Mais attention, les configurations mises en place fonctionnent sur d'anciennes version de Fail2ban et ne permettent pas de lire les traces pour une version 0.10.2 par exemple.