Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
pratique:informatique:parefeu:reaction [04/10/2024 19:05] – [Installation et lancement automatique] Zatalyzpratique:informatique:parefeu:reaction [14/07/2025 16:57] (Version actuelle) – [Démarrage automatique] Zatalyz
Ligne 12: Ligne 12:
 J'utilise la syntaxe jsonnet, qui est la plus complète et lisible à mes yeux. Ma config se met dans ''/etc/reaction/server.jsonnet'' J'utilise la syntaxe jsonnet, qui est la plus complète et lisible à mes yeux. Ma config se met dans ''/etc/reaction/server.jsonnet''
 </WRAP> </WRAP>
 +
 +===== Commandes de base =====
 +Commandes:
 +  * **''start''** : Démarre le démon Reaction
 +    * ''reaction start [OPTIONS] --config <CONFIG>''
 +    * Options possibles : ''-c'' (**Requis**), ''-l'', ''-s'', ''-h''
 +    * Par exemple, pour un fichier ''reaction start -c /etc/reaction/server.jsonnet''
 +    * Et un dossier : ''reaction start -c /etc/reaction/''
 +    * Dans le cas des dossiers, les seuls fichiers du dossier qui seront lus automatiquement
 +      * Doivent se terminer par les extensions ''.json'', ''.jsonnet'', ''.yml'' ou ''.yaml''.
 +      * Ne doivent pas démarrer par ''.'' ou ''_''.
 +  * **''show''** : Affiche les correspondances actuelles et les actions (= qui est banni)
 +    * ''reaction show [OPTIONS] [NAME=PATTERN]''
 +    * ''[NAME=PATTERN]'' : n'affiche que les éléments correspondant à name=PATTERN regex
 +    * Options possibles : ''-s'', ''-f'', ''-l'', ''-h''
 +  * **''flush''** : Retire une cible de Reaction (unban)
 +    * ''reaction flush [OPTIONS] [NAME=PATTERN]''
 +    * Options possibles : ''-s'', ''-f'', ''-l'', ''-h''
 +    * Débannir quelqu'un : ''reaction flush IP''
 +  * **''test-regex''** : Tester une regex
 +    * reaction test-regex --config <CONFIG> <REGEX> [LINE]
 +    * Arguments:
 +      * <REGEX>  Regex to test
 +      * [LINE]   Line to be tested
 +    * Options possibles : ''-c'' (**requis**), ''-h''
 +  * **''test-config''** : Tester une configuration
 +    * ''reaction test-config [OPTIONS] --config <CONFIG>''
 +    * Options possibles : ''-c'' (**requis**), ''-f'', ''-v'', ''-h''
 +  * **''help''**, ''-h'' : Affiche l'aide sur les commandes et sous-commandes
 +  * **''-V''**, ''--version'' : Affiche la version de reaction
 +
 +Pour les options possibles (suivant les commandes) : 
 +  * ''-c'', ''--config <CONFIG>'' : Fichier de configuration en format json, jsonnet ou yaml ; ou dossier contenant ces fichers. Requis.
 +  * ''-l'', ''--loglevel <LOGLEVEL>'' : Niveau de log minimum à afficher [default: INFO].
 +  * ''-s'', ''--socket <SOCKET>'' : chemin d'accès au socket de communication client-daemon [default: /run/reaction/reaction.sock].
 +  * ''-h'', ''--help'' : Affiche l'aide.
 +  * ''-f'', ''--format <FORMAT>'' : comment formater la sortie [default: yaml] [valeurs possibles : json, yaml].
 +  * ''-v'', ''--verbose'' : affiche plus d'infos en sortie.
 +
 +==== Les plus fréquement utilisées ====
 +
 +Voir qui est banni :
 +
 +  reaction show
 +
 +Débannir quelqu'un :
 +
 +  reaction flush IP
 +
 +Tester le dossier de configuration :
 +  reaction test-config -c /etc/reaction
 +
 +Démarrer (sans systemd) : 
 +  reaction start -c /etc/reaction/
 +
 +==== Base de donnée ====
 +
 +Par défaut les bases de données sont dans ''/var/lib/reaction/'' (''reaction-matches.db'' et ''reaction-flushes.db''). Les effacer remet tout à zéro.
  
 ===== Installation et lancement automatique ===== ===== Installation et lancement automatique =====
-Pour l'installer, il y a un [[https://framagit.org/ppom/reaction/-/releases/|paquet debian]] mais pas dans les dépôts. Installer aussi Minisign pour vérifier l'intégrité. Ci-dessous en exemple mais la page des releases donne les bons numéros de release...+Pour l'installer, il y a un [[https://framagit.org/ppom/reaction/-/releases/|paquet debian]] mais pas dans les dépôts. Installer aussi Minisign pour vérifier l'intégrité. Ci-dessous en exemple mais la page des releases donne les bons numéros de release (et les instructions)... J'utilise wget plutôt que curl, ce dernier ayant quelques soucis de sécurité (et puis wget est déjà de base sur mon serveur).
  
 <code>sudo apt install minisign <code>sudo apt install minisign
Ligne 23: Ligne 81:
   sudo apt install ./reaction_1.4.1-1_amd64.deb   sudo apt install ./reaction_1.4.1-1_amd64.deb
 </code> </code>
-   + 
-Ensuite on crée un fichier de config, on le modifie, et aussi un truc pour systemd.+Ensuite on crée le ou les fichiers de config, et on les bidouillent. Voir plus bas la/les confs.
   sudo mkdir /etc/reaction/   sudo mkdir /etc/reaction/
   sudo nano /etc/reaction/reaction.jsonnet   sudo nano /etc/reaction/reaction.jsonnet
-(voir plus bas la/les confs). 
  
-  sudo nano /etc/systemd/system/reaction.service+==== Démarrage automatique ==== 
 + 
 +<WRAP center round tip 100%> 
 +Avant de démarrer  automatiquement le service, c'est pas mal de tester sa configuration en lançant seulement la ligne de démarrage dans le terminal, ce qui casse à la première erreur : 
 +  sudo reaction start -c /etc/reaction/server.jsonnet 
 + 
 +On peut aussi vérifier la syntaxe avec : 
 +  sudo reaction test-config -c /etc/reaction 
 +</WRAP> 
 + 
 +<WRAP center round info 100%> 
 +Avec la version 2 il y a un à présent un service systemd déjà fourni. Il se trouve sur /lib/systemd/system/reaction@.service. 
 + 
 +Je laisse La vieille doc "pour mémoire" mais ce n'est plus forcément utile.  
 +</WRAP> 
 + 
 +Après installation et vérification, pour utiliser systemd : 
 + 
 +<code>sudo systemctl daemon-reload 
 +sudo systemctl enable --now reaction@reaction 
 +</code> 
 + 
 +Ce qui suit après le @ est le chemin vers la configuration dans /etc/ ; comme je lui fais lire le dossier, c'est donc juste "reaction" pour "/etc/reaction".  
 + 
 +<WRAP center round alert 100%> 
 +Je vais créer deux services : un pour Reaction proprement dit, un pour avertir en cas de plantage. Vu que j'ai eu des plantages muets, je lui dis de se relancer si ça lui arrive((Je précise que ça date des premières versions du logiciel, qui a bien évolué depuis.)) et sinon, j'ai une alerte. 
 + 
 + 
 +<code bash /etc/systemd/system/reaction.service> 
 +[Unit] 
 +Description=Reaction to ban bad ip 
 +After=network.target 
 +# Alerte si ça "fail" 
 +OnFailure=reaction-alert.service
  
-<code> 
 [Install] [Install]
 WantedBy=multi-user.target WantedBy=multi-user.target
 +
 [Service] [Service]
-ExecStart=/usr/bin/reaction start -c /etc/reaction/server.jsonnet+ExecStart=/usr/bin/reaction start -c /etc/reaction/
 StateDirectory=reaction StateDirectory=reaction
 RuntimeDirectory=reaction RuntimeDirectory=reaction
-WorkingDirectory=/var/lib/reaction+WorkingDirectory=/var/lib/reaction 
 Restart=on-failure Restart=on-failure
 RestartSec=3 RestartSec=3
 +# Anti-flood de redémarrage en boucle
 +StartLimitIntervalSec=400
 +StartLimitBurst=3
 </code> </code>
  
-Vu que j'ai eu des plantages muets, je lui dis de se relancer si ça lui arrive.+<code bash /etc/systemd/system/reaction-alert.service> 
 +[Unit] 
 +Description=Envoie une alerte si Reaction plante
  
-Et puis on y lance :  +[Service] 
-<code>sudo systemctl enable reaction.service +Type=oneshot 
-sudo service reaction start</code>+ExecStart=/usr/local/bin/reaction-alert.sh 
 +</code>
  
-<WRAP center round tip 60%> +Et le script pour envoyer un mail (ça aurait pu être autre chosemais j'aime bien les mails).  
-Mais avant de démarrer le servicec'est pas mal de tester sa configuration en lançant seulement la ligne de démarrage dans le terminal, ce qui casse à la première erreur : +<code> 
-  sudo reaction start -c /etc/reaction/server.jsonnet +#!/bin/bash 
-</WRAP>+LOCKFILE="/tmp/reaction-alert.lock" 
 +# Délai en minutes, donc 3 h = 180 
 +DELAY=180
  
-===== Commandes de base ===== +# Si une alerte a déjà été envoyée il y a moins de $DELAY, on quitte 
-Voir qui est banni : +if [ -e "$LOCKFILE" ] && [ "$(find "$LOCKFILE" -mmin -lt $DELAY)" ]; then 
-  reaction show+    logger -t reaction-alert "Notification de plantage de Reaction déjà envoyée récemment, aucune alerte renvoyée." 
 +    exit 0 
 +fi
  
-Débannir quelqu'un : +touch "$LOCKFILE"
-  reaction flush IP+
  
-Consulter l'aide : +SUBJECT="Reaction planté sur $(hostname)" 
-  reaction --help +TO="monemail@domaine.org" 
-===== Envoyer des mails quand il y une action ===== +BODY="Le service Reaction sur $(hostnamesemble avoir un souci.  
-J'ai une commande qui va envoyer un mail via un script, en ayant en paramètre deux variables : ''ip'' (l'ip bannie) et ''rule'' (la raison du bannissement). +Arrêt à $(date). 
-<code>local sendmail(ip,rule= { +" 
-  mail: { + 
-    cmd: ['sh', '/root/scripts/sendmailreaction/mailreaction.sh', ip, rule], +echo "$BODY" | mail -s "$SUBJECT" "$TO" 
-  }, +logger -t reaction-alert "Alerte envoyée par mail à $TO pour le plantage de Reaction"
-};+
  
 </code> </code>
  
-Le script +On démarre le service :  
-<code>#!/bin/bash +<code>sudo systemctl enable reaction.service 
-# Envoyer un mail +sudo service reaction start</code> 
-dossiermail="/root/scripts/sendmailreaction/mail" +</WRAP>
-titremail="$1 banni" +
-# Création du fichier du corps du mail dans un fichier temporaire qui évite toute collision +
-corpmail="$(mktemp -p $dossiermail)" +
-listeip="/var/lib/reaction/reaction-matches.db"+
  
-# Vérifier si l'adresse a déjà été banni pour éviter de flooder lorsqu'on relance 
-if grep -q $1 $listeip; then 
-    exit 
-else 
-    # Message pour le corps du mail 
-    echo "Méchant $1 ! $2 \n \n" >> $corpmail 
-    # Ajouter les logs pour les détails 
-    journalctl --since yesterday | grep $1 >> $corpmail 
-    #Envoyer le mail 
-    cat $corpmail | mail -s "$titremail" root 
-    # Effacer le corps du crime pour éviter d'encombrer sans intérêt 
-    rm $corpmail 
-fi</code> 
  
-Penser évidement à créer les dossiers ''/root/scripts/sendmailreaction/'' et ''/root/scripts/sendmailreaction/mail'' avant de lancer le reste.+==== Envoyer un mail en cas de plantage ====
  
-Plus loin dans le fichier de configuration de Reaction, dans les streams, comment dire qu'il faut envoyer un mail (exemple sur ssh) : 
-<code>  streams: { 
-    ssh: { 
-      cmd: ['journalctl', '-fn0', '-u', 'ssh.service'], 
-      filters: { 
-        failedlogin: { 
-          regex: [ 
-            @'authentication failure;.*rhost=<ip>', 
-            @'Connection reset by authenticating user .* <ip>', 
-            @'Failed password for .* from <ip>', 
-          ], 
-          retry: 6, 
-          retryperiod: '6h', 
-          actions: banFor('48h') + sendmail('<ip>','"Banni 48h pour tentative de co à SSH"'), 
-        }, 
-      }, 
-    }, 
-</code> 
  
-===== Actions par défaut ===== +===== Configuration ===== 
-On peut créer des actions par défaut qu'on appelle ensuite ; cela permet par exemple de définir pour tout le monde la même durée de bannissement et de la changer à un seul endroit si besoin. +Pour la doc  complète, se référer à [[https://reaction.ppom.me/]]. Concernant ma configuration, je pars avec ces spécificités : 
 +  * Utilisation de nftables 
 +  * Découpage de la configuration par services (pour faciliter certaines automatisations) 
 +  * Analyse des ip bannies pour en déduire des plages et bannir ces dernières ?  
 +  * Rapport (journalier ?) sur les ip bannies (histoire de pouvoir suivre ce qui se passe et la charge) ?
  
-Ce n'est pas forcément pertinent pour tout, par exemple je préfère préciser la raison du bannissement pour savoir quels services se font attaquer.+Point côté syntaxe : dans les noms, on peut utiliser le tiret bas, mais pas de tiret classique, ça va faire des erreurs car jsonnet l'interprète... Donc "mon_filtre" est ok, pas "mon-filtre".  
 +==== Découpage des fichiers ==== 
 +Il s'agit de me simplifier un peu la lecture et la maintenance. Sur l'exemple ici, j'ai 3 types de fichiers 
 +  * Définitions : ce qu'est l'action pour bannir/débannirles périodes par défaut de bannissement... C'est le fichier ''_lib.jsonnet''
 +  * ''server.jsonnet'' qui contient les trucs de base : comment les ip sont formatées et ce qui se passe quand on démarre/arrête le service. 
 +  * Les fichiers de stream (''ssh.jsonnet'', ''web.jsonnet'', etc) qui vont lister, par service, quel fichier de log analyser et sur quelles regex on va bannir.
  
-On déclare la commande : +On paramètre évidement le lancement de Reaction (avec service ou direct en ligne de commande) pour lire tout le contenu du dossier (ici /etc/reaction). 
-<code> + 
-local filter_default { +=== server.jsonnet === 
-  retry: 3, +Ici c'est assez classiquele seul point important étant que je tourne avec nftables. Il peut être utile de spécifier les ip à ne pas bannir avec Reaction, couplé avec un fichier [[pratique:informatique:parefeu:nftables|nftables]] complet (entre autre sur la vérification des ip locales), ça évite de se bannir son propre routeur ou en tant que sysadmin. 
-  retryperiod: '6h', +
-  actionsbanFor('24h'), +
-}; +
-</code>+
  
-Et dans les streams, on l'appelle de cette façon :  +<code json server.jsonnet>
-<code>+
 { {
-  streams: { +  patterns: { 
-    ssh: { +    ip: { 
-      filters: { +    // Both IPv4 and IPv6, do not accept malformed IPs 
-        failedloginfilter_default + +      regex@'(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}|(?:(?:[0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(?:ffff(?::0{1,4}){0,1}:){0,1}(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])|(?:[0-9a-fA-F]{1,4}:){1,4}:(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9]))', 
-          regex: ['...']+      ignore: [ 
-        }+        // Ne pas oublier la virgule après chaque ip, pour l'énumération ;) 
-      },+        '127.0.0.1', 
 +        '::1', 
 +        // Sous-réseau d'une box 
 +        '192.168.1.0/24' 
 +        // Sous-réseau proxmox ? 
 +        //'10.0.0.0/8' 
 +        // Ip fixes de sysadmins 
 +        // ip de bastion 
 +      ],
     },     },
   },   },
 +
 +  start: [
 +    ['nft', |||
 +    table inet reaction {
 +      set ipv4bans {
 +        type ipv4_addr
 +        flags interval
 +        auto-merge
 +      }
 +      set ipv6bans {
 +        type ipv6_addr
 +        flags interval
 +        auto-merge
 +      }
 +      chain input {
 +        type filter hook input priority 0
 +        policy accept
 +        ip saddr @ipv4bans drop
 +        ip6 saddr @ipv6bans drop
 +      }
 +    }
 +||| ],
 +  ],
 +  stop: [
 +    ['nft', 'delete table inet reaction'],
 +  ],
 } }
 +
 </code> </code>
-===== Découper la configuration ===== 
-On peut tout mettre dans un seul fichier, moi j'aime bien séparer pour m'y retrouver. Faut avouer que je prévois max de regex à un moment, et max de services couverts aussi. 
  
 +=== _lib.jsonnet : actions par défaut ===
 +Ce fichier sert à définir les actions telles que "banFor", qu'on configure évidement avec notre commande pour nftables((Cela m'a valu quelques erreurs en recopiant trop bêtement la doc officielle, qui est pour iptable...)). 
  
 +On peut ainsi définir des actions par défaut : combien de temps on bannit, combien de lignes dans les logs avant de bannir, etc. Cela permet par exemple de définir pour tout le monde la même durée de bannissement et de la changer à un seul endroit si besoin. 
  
-Dans le fichier principalon peut appeler un autre fichier avec cette syntaxe : +Le fait que le fichier commence par "_" fait qu'il ne sera pas lu automatiquement au lancement de Reactionil faudra l'appeler là où il est utile (dans les streams). Si on ne fais pas ça (s'il est noté "lib.jsonnet" par exemple)on aura l'erreur "ERROR While reading ssh.jsonnet in /etc/reaction: variable is not defined: filter_default" lors de l'execution.
-<code>+
-  streams: { +
-    ssh: import 'ssh.jsonnet', +
-  }, +
-}</code> +
- +
-et ''ssh.jsonnet'' va contenir notre morceau propre au stream +
- +
-<WRAP center round todo 60%> +
-Mais j'ai du manquer un bout, ça me fait des erreurs ça... Il ne reconnait pas le "banfor" pourtant déclaré dans le fichier principal. +
-</WRAP>+
  
-===== Mes bouts de stream et de config ===== +<code json _lib.jsonnet>
-Fichier principal +
-<code jsonnet server.jsonnet> +
-// This file is using JSONNET, a complete configuration language based on JSON // See https://jsonnet.org +
-// action pour bannir/débannir+
 local banFor(time) = { local banFor(time) = {
   ban: {   ban: {
-    cmd: ['ip46tables', '-w', '-A', 'reaction', '-s', '<ip>', '-j', 'DROP'],+    cmd: ['nft46', 'add element inet reaction ipvXbans { <ip> }'],
   },   },
   unban: {   unban: {
 +    cmd: ['nft46', 'delete element inet reaction ipvXbans { <ip> }'],
     after: time,     after: time,
-    cmd: ['ip46tables', '-w', '-D', 'reaction', '-s', '<ip>', '-j', 'DROP'], 
   },   },
 }; };
  
-// Envoyer un mail lors des actions et précisant ip et raison +// retry et retryperiod sont quand il y a plusieurs tentatives autorisées 
-local sendmail(ip,rule) = { +// juste mettre le banFor sinon... 
-  mail{ + 
-    cmd['sh', '/root/scripts/sendmailreaction/mailreaction.sh', ip, rule]+// Filtre (et optionspar défaut : ni trop doux, ni trop cruel. 
-  },+local filter_default = { 
 +  retry3, 
 +  retryperiod: '3h', 
 +  actions: banFor('48h'),
 }; };
  
-// pourquoi ça ouvre ici ? Mais, ça marche. +// Filtre doux c'est peut-être légitime. Et peut-être pas
-+local filter_soft = 
-// patterns are substitued in regexes. when a filter performs an action, it replaces the found pattern. +  retry6, 
-// reaction regex syntax is defined herehttps://github.com/google/re2/wiki/Syntax +  retryperiod: '3h', 
-// jsonnet's @'string' is for verbatim strings+  actionsbanFor('10s')
-  patterns: +};
-    // IPs can be IPv4 or IPv6 +
-    // ip46tables (C program also in this repo) handles running the good commands +
-    ip{ +
-      regex@'(([0-9]{1,3}\.){3}[0-9]{1,3})|([0-9a-fA-F:]{2,90})', +
-      ignore['127.0.0.1', '::1']+
-    }+
-  },+
  
-// Commandes exécutées au lancement +// Filtre violent un seul essaibanni un mois. 
-  start+local filter_hard = { 
-    ['ip46tables', '-w', '-N', 'reaction']+  actionsbanFor('720h')
-    ['ip46tables', '-w', '-I', 'INPUT', '-p', 'all', '-j', 'reaction'], +};
-    ['echo', 'Le service a démarré', '|', 'mail', '-s', '"Démarrage de Reaction"', 'root'], +
-  ], +
-  // Commandes exécutées à l'arrêt, après tout le reste +
-  stop+
-    ['ip46tables', '-w', '-D', 'INPUT', '-p', 'all', '-j', 'reaction']+
-    ['ip46tables', '-w', '-F', 'reaction'], +
-    ['ip46tables', '-w', '-X', 'reaction'], +
-    ['echo', 'Le service est éteint', '|', 'mail', '-s', '"Extinction de Reaction"', 'root'], +
-  ],+
  
-// Streams : c'est là qu'on va définir les services et règles menant au bannissement +local stream_name(name) ={ 
-  streams: { +  reason: { 
-    sshimport 'ssh.jsonnet', +    cmd['logger', 'REACTION BLOCK <ip> because: ', name], 
-    kernelimport 'kernel.jsonnet', +  }, 
-    badguypostfiximport 'badguypostfix.jsonnet'+}; 
- },+ 
 +// Exposer les définitions précédentes pour qu'elles soient accessibles depuis un autre fichier Jsonnet 
 +
 +  banFor: banFor
 +  filter_defaultfilter_default
 +  filter_soft: filter_soft, 
 +  filter_hard: filter_hard, 
 +  stream_name: stream_name,
 } }
 +
 </code> </code>
  
-Pour ssh et kernelil s'agit des configurations par défaut auxquelles j'ai ajouté mon envoi de mail : + 
-<code jsonnet ssh.jsonnet> + 
-    { +=== Streams === 
-      cmd: ['journalctl', '-fn0', '-u', 'ssh.service'],+Je met ici une config très basique pour ssh (<wrap todo>Faudra que je mette le tout sur une forgeune fois fini...</wrap>), suffisante pour lister les "pièges" dans la syntaxe. 
 + 
 +<code json ssh.jsonnet> 
 +local lib = import '_lib.jsonnet'; 
 +
 +  streams: { 
 +    ssh: 
 +      cmd: ['journalctl', '-fn0', '-u', 'sshd.service'],
       filters: {       filters: {
-        failedlogin: {+        failedlogin: lib.filter_default + {
           regex: [           regex: [
             @'authentication failure;.*rhost=<ip>',             @'authentication failure;.*rhost=<ip>',
Ligne 233: Ligne 323:
             @'Failed password for .* from <ip>',             @'Failed password for .* from <ip>',
           ],           ],
-          retry: 6,+          retry: 3,
           retryperiod: '6h',           retryperiod: '6h',
-          actions: banFor('48h') + sendmail('<ip>','"Banni 48h pour tentative de co à SSH"'),+          actions: lib.banFor('48h'),
         },         },
       },       },
     },     },
 +  }, 
 +}
 </code> </code>
  
-<code jsonnet kernel.jsonnet> +  * ''local lib = import '_lib.jsonnet';'' =il est nécessaire d'appeler le fichier avec les définitions pour la suite, et on fait une variable pour les appels la concernant (''lib'')
-    // Ban hosts which knock on closed ports+  ''cmd: ['journalctl', '-fn0', '-u', 'sshd.service']'' => indique quel fichier de log lire. 
-    // It needs this iptables chain to be used to drop packets: +  * ''lib.filter_default'' et ''lib.banFor'' : on utilise les actions ''banFor'' et ''filter_default'' mais comme elles sont dans le fichier ''_lib.jsonnet''on appelle la variable définie avant (''lib''). Sinon, ben... ça marche pas. 
-    // ip46tables -N log-refuse + 
-    // ip46tables -A log-refuse -p tcp --syn -j LOG --log-level info --log-prefix 'refused connection: ' +Concernant l'appel des diverses fonctions, il y a plein de petites subtilités. Par exemple, si on veut appliquer les actions par défaut (même durée de ban, même valeurs pour retry, retryperiod) mais déclarer une action complémentaire comme "stream_name", alors on fait ceci  
-    // ip46tables -A log-refuse -m pkttype ! --pkt-type unicast -j nixos-fw-refuse + 
-    // ip46tables -A log-refuse -j DROP +<code> 
-    { +[...] 
-      cmd: ['journalctl', '-fn0', '-k'], +        apache_authlib.filter_default + 
-      filters{ +          regex: [ 
-        portscan: { +            @'^.*client <ip>.* regex', 
-          regex: ['refused connection: .*SRC=<ip>']+          ]
-          retry: 4, +          actions: lib.filter_default.actions lib.stream_name('apache_auth'),
-          retryperiod: '6h'+
-          actions: banFor('720h'sendmail('<ip>','"est banni un mois pour avoir fait un truc louche sur un port fermé"'),+
         },         },
-      }+[...] 
-    },+</code> 
 +Ici ''lib.filter_default.actions'' précise qu'il faut appliquer les actions par défaut de "filter_default". ''+ lib.stream_name('apache_auth')'' permet d'ajouter l'action stream_name (qui permet de loguer pour "quoi" on a banni)en précisant une raison personnalisée donc. Il faut quand même déclarer ''lib.filter_default'' au niveau du stream (après "apache_auth" dans l'exemple), afin que les paramètres "retry" et "retryperiod" s'appliquent sur le stream.  
 +==== Réaliser des actions plus compliqués ==== 
 +Lorsqu'il y a bannissement via Reaction, j'aimerais pouvoir réaliser certaines actionscomme être avertie par mail. 
  
 +Bon, en vrai, ça dépend. Sur certains services, la surveillance via des mails, au début, permet d'affiner les règles et éviter les faux positifs. Ensuite, ça fait surtout du bruit. Il devient alors plus utile de loguer les ip bannies, et de vérifier s'il y a des schémas : même plages d'ip par exemple. Ou ip qui continuent d'être bannies mois après mois. 
  
 +Bref, tout ça va se faire via notre fichier _lib.jsonnet, avec des actions diverses.
 +
 +=== Lancer un script ===
 +Si on veut bannir ET réaliser une action autre dans la foulée (par exemple envoyer un mail), le plus simple sera finalement de faire un script de ce type : 
 +
 +<code bash _ban.sh>
 +#!/bin/bash
 +# Bannissement
 +nft46 add element inet reaction ipvXbans { "$1" }
 +
 +# Envoi d'un mail
 +# cf le script plus bas...
 </code> </code>
  
-Pour postfix, pour le moment je cible certains bot cons+On modifie alors _lib.jsonnet sur la partie cmd : 
-<code jsonnet badguypostfix.jsonnet> +<code json _lib.jsonnet> 
-    { +local banFor(time) = { 
-      cmd: ['journalctl', '-fn0', '-u', 'postfix@-.service'],+  ban: { 
 +    cmd: ['nft46''add element inet reaction ipvXbans { <ip> }'], 
 +  } 
 +</code> 
 +devient  
 +<code json _lib.jsonnet> 
 +local banFor(time) = { 
 +  ban: { 
 +    cmd: ['sh', '-c', '/etc/reaction/_ban.sh <ip>'], 
 +  } 
 +</code> 
 + 
 +Ce qui autorise toutes les fantaisies. 
 + 
 +=== Action : envoi de mail === 
 +On peut aussi déclarer une action spéciale pour l'envoi de mail, ce qui permet de l'appeler dans les streams et de personnaliser le message en rapport avec le filtre déclenché 
 + 
 +Le script suivant prend deux variables : ''ip'' (l'ip bannie) et ''rule'' (la raison du bannissement). 
 + 
 +<code json _lib.jsonnet>local sendmail(ip,rule) = { 
 +  mail: { 
 +    cmd: ['sh', '/etc/reaction/_mail.sh', ip, rule], 
 +  }, 
 +}; 
 +</code> 
 + 
 +Le script : 
 +<code>#!/bin/bash 
 +# Envoyer un mail 
 +dossiermail="/root/scripts/sendmailreaction" 
 +titremail="$1 banni" 
 +# Création du fichier du corps du mail dans un fichier temporaire qui évite toute collision 
 +corpmail="$(mktemp -p $dossiermail)" 
 +listeip="/var/lib/reaction/reaction-matches.db" 
 + 
 +# Vérifier si l'adresse a déjà été banni pour éviter de flooder lorsqu'on relance 
 +if grep -q $1 $listeip; then 
 +    exit 
 +else 
 +    # Message pour le corps du mail 
 +    echo "Méchant $1 ! $2 \n \n" >> $corpmail 
 +    # Ajouter les logs pour les détails 
 +    journalctl --since yesterday | grep $1 >> $corpmail 
 +    #Envoyer le mail 
 +    cat $corpmail | mail -s "$titremail" root 
 +    # Effacer le corps du crime pour éviter d'encombrer sans intérêt 
 +    rm $corpmail 
 +fi</code> 
 + 
 +Penser évidement à créer le dossier ''/root/scripts/sendmailreaction/'' avant de lancer le reste. 
 + 
 +Dans les streams (en ayant des fichiers modulaires), comment dire qu'il faut envoyer un mail (exemple sur ssh) : 
 +<code>  streams: { 
 +    ssh: 
 +      cmd: ['journalctl', '-fn0', '-u', 'ssh.service'],
       filters: {       filters: {
-        badguy: {+        failedlogin: {
           regex: [           regex: [
-            @'^.* improper command pipelining after CONNECT from unknown\[<ip>\].*', +            @'authentication failure;.*rhost=<ip>', 
-            @'^.*\[<ip>\].*tiscali.it.*', +            @'Connection reset by authenticating user .* <ip>', 
-            @'^.* NOQUEUE: reject: RCPT from unknown\[<ip>\]: 504 5.5.2 .* Helo command rejected: need fully-qualified hostname; .*', +            @'Failed password for .* from <ip>',
-            @'^.*connect from .*censys.*\[<ip>\]', +
-            @'^.*connect from .*stretchoid.*\[<ip>\]',+
           ],           ],
-          retry: 1,+          retry: 6,
           retryperiod: '6h',           retryperiod: '6h',
-          actions: banFor('720h') + sendmail('<ip>','"Banni un mois sans seconde chance pour avoir mal causé à Postfix"'),+          actions: lib.banFor('48h') + lib.sendmail('<ip>','"Banni 48h pour tentative de co à SSH"'),
         },         },
       },       },
pratique/informatique/parefeu/reaction.1728061541.txt.gz · Dernière modification : 04/10/2024 19:05 de Zatalyz