Configuration Logstash - Fail2ban
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 en 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é.
Sommaire
Votre avis
Nobody voted on this yet
|
|
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.
Groupe
Le nouveau groupe loganalyzer
est créé afin de faciliter la gestion des droits d'accès.
#sudo groupadd --system loganalyzer
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
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*
Configuration
Attention, la configuration doit être adaptée en fonction des version de
Fail2ban
installée. En effet, le contenu des fichiers traces peut varier.
Configuration mapping
Dans le cadre de cet article, des indexes personnalisés sont utilisés. Afin de bénéficier de toutes les fonctionnalitées, comme la géolocalisation, il est nécessaire de déclaration le mapping pour ces indexes. La déclaration s'effectue comme décrit dans l'article suivant.
La définition du modèle s'inspire de celui qui est créé par défaut lors du démarrage de Logstash
, à savoir le modèle logstash
.
#curl -X GET "localhost:9200/_template/logstash?pretty" { "logstash" : { "order" : 0, "version" : 60001, "index_patterns" : [ "logstash-*" ], "settings" : { "index" : { "refresh_interval" : "5s" } }, "mappings" : { "_default_" : { "dynamic_templates" : [ { "message_field" : { "path_match" : "message", "match_mapping_type" : "string", "mapping" : { "type" : "text", "norms" : false } } }, { "string_fields" : { "match" : "*", "match_mapping_type" : "string", "mapping" : { "type" : "text", "norms" : false, "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } } ], "properties" : { "@timestamp" : { "type" : "date" }, "@version" : { "type" : "keyword" }, "geoip" : { "dynamic" : true, "properties" : { "ip" : { "type" : "ip" }, "location" : { "type" : "geo_point" }, "latitude" : { "type" : "half_float" }, "longitude" : { "type" : "half_float" } } } } } }, "aliases" : { } } }
Pour le modèle personnalisé, les modifications apportées portent sur le nom, soit fail2ban
, et le périmètre d'application sur les indexes sont le nom commence par f2b-
. La configuration du mapping standard est intégralement reprise.
#curl -X PUT "localhost:9200/_template/fail2ban" -H 'Content-Type: application/json' -d' { "order" : 0, "version" : 1, "index_patterns" : [ "f2b-*" ], "settings" : { "index" : { "refresh_interval" : "5s" } }, "mappings" : { "_default_" : { "dynamic_templates" : [ { "message_field" : { "path_match" : "message", "match_mapping_type" : "string", "mapping" : { "type" : "text", "norms" : false } } }, { "string_fields" : { "match" : "*", "match_mapping_type" : "string", "mapping" : { "type" : "text", "norms" : false, "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } } ], "properties" : { "@timestamp" : { "type" : "date" }, "@version" : { "type" : "keyword" }, "geoip" : { "dynamic" : true, "properties" : { "ip" : { "type" : "ip" }, "location" : { "type" : "geo_point" }, "latitude" : { "type" : "half_float" }, "longitude" : { "type" : "half_float" } } } } } }, "aliases" : { } } ' {"acknowledged":true}
A noter les configurations spécifiques des propriétés. location
sera utilisée pour référencer les données de géolocalisation et ip
est déclaré en type ip
.
La réponse {"acknowledged":true}
indique que le modèle a été correctement installé, ainsi que le mapping associé.
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.
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
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:ip}" ]
add_tag => [ "%{action}" ]
named_captures_only => true
}
if "_grokparsefailure" in [tags] {
drop { }
}
date {
match => [ "bantime", "ISO8601" ]
target => "bantime"
}
geoip {
source => "ip"
}
}
}
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 champbantime
; -
%{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 champjail
; -
%{WORD:action}
permet d'extraire l'action et de stocker la valeur dans le champaction
; -
%{IPV4:ip}
permet d'extraire l'adresse IP et de stocker la valeur dans le champip
.
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;
- ip.
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 ip
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:ip}" ]
add_tag => [ "%{action}" ]
named_captures_only => true
}
if "_grokparsefailure" in [tags] {
drop { }
}
date {
match => [ "bantime", "ISO8601" ]
target => "bantime"
}
geoip {
source => "ip"
}
}
}
output {
elasticsearch {
hosts => ["localhost:9200"]
index => "f2b-%{+YYYY.MM}"
}
}
A noter le nom de l'index est f2b-%{+YYYY.MM}
afin de rentrer dans le cadre du mapping préalablement mis en place, s'applicant aux indexes commençant par f2b-
. La variable %{+YYYY.MM}
sera substituée par l'année et le numéro de mois.
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.