Synology fail2ban ban l'IP, mais ne bloque pas (docker swag)

hydrogenation_moskito

Nouveau membre
2 Février 2023
5
1
1
Bonjour,

SWAG tourne sur mon DS920+ (DSM 7), et fail2ban détecte bien lorsque la limite de tentatives de connexion a été atteinte :
2023-02-01_15_26_31-SWAG_Dashboard_Mozilla_Firefox.png
sur le dashboard de swag, je vois bien l'adresse IP qui a été flaggé et "jailé", mais en pratique, je peux toujours me connecter.

Je viens demander de l'aide sur ce forum car après de multiples recherches en ligne, je n'ai pas trouvé de résultats concluants. Je suis tombé sur l'un des posts sur ce forum, où un modérateur (MilesTEG1) conseillait de demander directement dans cette partie du forum, dédié à Synology, raison pour laquelle je fais ce post ajd. N'hésitez pas à me rediriger si je poste au mauvais endroit.

Voici mon fichier `jail.local`:

Code:
## Version 2022/08/20

[DEFAULT]
ignoreip = 10.0.0.0/8
           192.168.0.0/16
           172.27.0.0/12
                   127.0.0.1/8
banaction = iptables-allports
bantime  = 60
findtime  = 60
maxretry = 5

[ssh]
enabled = false

[nginx-http-auth]
enabled  = true
filter   = nginx-http-auth
port     = http,https
logpath  = /config/log/nginx/error.log

[nginx-badbots]
enabled  = true
port     = http,https
filter   = nginx-badbots
logpath  = /config/log/nginx/access.log
maxretry = 2

[nginx-botsearch]
enabled  = true
port     = http,https
filter   = nginx-botsearch
logpath  = /config/log/nginx/access.log

[nginx-deny]
enabled  = true
port     = http,https
filter   = nginx-deny
logpath  = /config/log/nginx/error.log

[nginx-unauthorized]
enabled  = true
chain = DOCKER-USER
port     = http,https
filter   = nginx-unauthorized
logpath  = /config/log/nginx/access.log

[jellyfin]
backend = 


enabled = true
chain = DOCKER-USER
port = http, https
protocol = tcp
filter = jellyfin
logpath = /jellyfin/log/log_*.log

Quelques précisions :
- Afin que mes services voient bien les véritables adresses IP et non pas les IP internes docker, j'ai dû exécuter 2 commandes iptables, comme expliqué dans ce guide.
- vous remarquerez que j'ai ajouté `chain = DOCKER-USER`, dans la config `[nginx-unauthorized]`, et la config `[jellyfin]`. C'est suite à ce commentaire que j'ai lu sur une issue github. Malheureusement, même suite à ça, le problème persiste.

Merci d'avance.
 
Quelques précisions :
- Afin que mes services voient bien les véritables adresses IP et non pas les IP internes docker, j'ai dû exécuter 2 commandes iptables, comme expliqué dans ce guide.
- vous remarquerez que j'ai ajouté `chain = DOCKER-USER`, dans la config `[nginx-unauthorized]`, et la config `[jellyfin]`. C'est suite à ce commentaire que j'ai lu sur une issue github. Malheureusement, même suite à ça, le problème persiste.
Hello,
Je n'ai jamais eu besoin de faire ces manip... mais je n'ai pas tout à fait la même configuration :
  • mon swag est en macvlan
  • le fail2ban que j'utilise n'est pas celui intégré à swag, mais l'image de crasymax, installée en host
  • mon adguard home est ausi en macvlan.
Sinon, j'ai un fichier common.local que j'inclue dans tous mes fichiers jails :
Config Apache:
[DEFAULT]
# "ignoreip" can be an IP address, a CIDR mask or a DNS host. Fail2ban will not
# ban a host which matches an address in this list. Several addresses can be
# defined using space separator.
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 192.168.0.0/16 172.16.0.0/12

# Changes the default ban action from "iptables-multiport", which causes issues on some platforms, to "iptables-allports".
# banaction = %(banaction_allports)s
banaction = iptables-allports
action = %(action_mwl)s

# "bantime.increment" allows to use database for searching of previously banned ip's to increase a
# default ban time
bantime.increment = true
# "bantime.maxtime" is the max number of seconds using the ban time can reach (doesn't grow further)
bantime.maxtime = 5w
# "bantime.factor" is a coefficient to calculate exponent growing of the formula or common multiplier
bantime.factor = 24
# "bantime" is the number of seconds that a host is banned.
bantime  = 600
# A host is banned if it has generated "maxretry" during the last "findtime"
# seconds.
findtime  = 600
# "maxretry" is the number of failures before a host get banned.
maxretry = 5

destemail = mail@machin.com
dest = mail@machin.com
sender = mail@machin.com
sendername = Fail2Ban-Docker

Essaye de reprendre le banaction et le action.
 
Salut,
Comment a tu instalé SWAG ? Si c'est via docker-compose pourrai tu partager ton compose ( enleve les éléments privés, nom de domaine, token, ... )
 
Merci de vos réponses.

mon swag est en macvlan
Je ne suis pas assez à l'aise en réseau/docker pour setup un macvlan malheureusement, du moins, pour le moment.

le fail2ban que j'utilise n'est pas celui intégré à swag, mais l'image de crasymax, installée en host
Intéressant, du coup, tu as désactivé le fail2ban de swag ? Ou tu n'as même pas SWAG ?

Essaye de reprendre le banaction et le action.
Merci, je vais tester cela ce soir, une fois chez moi. Je reposterai l'issue.

Comment a tu instalé SWAG ? Si c'est via docker-compose pourrai tu partager ton compose ( enleve les éléments privés, nom de domaine, token, ... )
Via un "custom template" de portainer. Donc en gros, via docker-compose. Voici:

Code:
version: "2.1"
services:
  swag:
    image: linuxserver/swag:latest
    container_name: swag
    cap_add:
      - NET_ADMIN
    environment:
      - PUID=1024
      - PGID=100
      - TZ=Europe/Amsterdam
      - URL=<enlevé>
      - SUBDOMAINS=wildcard
      - VALIDATION=dns
      - CERTPROVIDER= #optional
      - DNSPLUGIN=njalla #optional
      - DUCKDNSTOKEN= #optional
      - EMAIL= #optional
      - ONLY_SUBDOMAINS=false #optional
      - EXTRA_DOMAINS= #optional
      - STAGING=false #optional
      - DOCKER_MODS=linuxserver/mods:swag-dashboard
    volumes:
      - /volume1/docker/swag/config:/config
      - /volume1/docker/jellyfin/config/log:/jellyfin/log:ro
    ports:
      - 443:443
      - 80:80 #optional
      - 8181:81  # for swag-dashboard
    restart: unless-stopped
    networks:
      - swag_nginx_reverse_proxy
networks:
  swag_nginx_reverse_proxy:
    external: true
 
Essaye de reprendre le banaction et le action.
Alors je viens de tester: j'ai donc edit mon `jail.local` et il avait déjà le même banaction (banaction = iptables-allports). J'ai donc juste rajouté le `action = %(action_mwl)s` et j'ai restart mon docker swag: malheureusement, tout comme avant, en spammant le login par url, je suis flaggé une fois de plus mais ne suis pas bloqué.

J'ai essayé d'autres pistes, car je suis tombé sur différents postes en lignes, aucun n'a résolu le problème, mais je partage tout de même car peut être que je n'ai pas fait convenablement et que vous pourrez me guider sur ce que je fais de faux:

Comme l'explique ce poste, il se peut que mon syno n'ai pas les modules iptables nécessaires. En outputant le fichier `/proc/net/ip_tables_targets`, je n'ai ni DROP ni REJECT. L'OP de ce post a résolu son problème en créeant un "local iptables blocktype config file", et en le settant à DROP. Malheureusement, je pense que, vu l'ancienneté de ce post, fail2ban a bien changé, car dans le dossier `/etc/fail2ban/action.d/`, aucun fichier .local mais que des fichiers .conf. J'ai essayé une première fois en créant ce fichier comme dans la solution du poste, mais évidemment, f2b n'a pas voulu restart, problème de formatting du fichier. J'ai donc essayé de modifier le seul fichier qui présentait une règle similaire, à savoir `/etc/fail2ban/action.d/iptables-common.conf`, qui avait 2 règles (init et init inet 6) à `blocktype = REJECT --reject-with icmp-port-unreacheable`. J'ai donc changé à `blocktype = DROP`. Mais après restart, rien n'a changé, toujours le même problème.

Autre piste, je me permets de partager les logs de fail2ban lorsque je tente de brute force la connexion:

Code:
2023-02-02 21:24:20,089 fail2ban.filter         [1447]: INFO    [nginx-unauthorized] Found 146.70.134.149 - 2023-02-02 21:24:19
2023-02-02 21:24:20,691 fail2ban.filter         [1447]: INFO    [nginx-unauthorized] Found 146.70.134.149 - 2023-02-02 21:24:20
2023-02-02 21:24:20,834 fail2ban.filter         [1447]: INFO    [jellyfin] Found 146.70.134.149 - 2023-02-02 21:24:20
2023-02-02 21:24:21,068 fail2ban.actions        [1447]: NOTICE  [nginx-unauthorized] Ban 146.70.134.149
2023-02-02 21:24:21,085 fail2ban.utils          [1447]: ERROR   7fab232f4510 -- exec: iptables -w -N f2b-nginx-unauthorized
iptables -w -A f2b-nginx-unauthorized -j RETURN
iptables -w -I DOCKER-USER -p tcp -j f2b-nginx-unauthorized
2023-02-02 21:24:21,085 fail2ban.utils          [1447]: ERROR   7fab232f4510 -- stderr: 'iptables: Chain already exists.'
2023-02-02 21:24:21,085 fail2ban.utils          [1447]: ERROR   7fab232f4510 -- stderr: 'iptables: No chain/target/match by that name.'
2023-02-02 21:24:21,085 fail2ban.utils          [1447]: ERROR   7fab232f4510 -- returned 1
2023-02-02 21:24:21,086 fail2ban.actions        [1447]: ERROR   Failed to execute ban jail 'nginx-unauthorized' action 'iptables-allports' info 'ActionInfo({'ip': '146.70.134.149', 'family': 'inet4', 'fid': <function Actions.ActionInfo.<lambda> at 0x7fab23733a60>, 'raw-ticket': <function Actions.ActionInfo.<lambda> at 0x7fab23734160>})': Error starting action Jail('nginx-unauthorized')/iptables-allports: 'Script error'
2023-02-02 21:24:21,116 fail2ban.actions        [1447]: NOTICE  [jellyfin] Ban 146.70.134.149
2023-02-02 21:24:21,132 fail2ban.utils          [1447]: ERROR   7fab230253a0 -- exec: iptables -w -N f2b-jellyfin
iptables -w -A f2b-jellyfin -j RETURN
iptables -w -I DOCKER-USER -p tcp -j f2b-jellyfin
2023-02-02 21:24:21,132 fail2ban.utils          [1447]: ERROR   7fab230253a0 -- stderr: 'iptables: Chain already exists.'
2023-02-02 21:24:21,132 fail2ban.utils          [1447]: ERROR   7fab230253a0 -- stderr: 'iptables: No chain/target/match by that name.'
2023-02-02 21:24:21,133 fail2ban.utils          [1447]: ERROR   7fab230253a0 -- returned 1
2023-02-02 21:24:21,133 fail2ban.actions        [1447]: ERROR   Failed to execute ban jail 'jellyfin' action 'iptables-allports' info 'ActionInfo({'ip': '146.70.134.149', 'family': 'inet4', 'fid': <function Actions.ActionInfo.<lambda> at 0x7fab23733a60>, 'raw-ticket': <function Actions.ActionInfo.<lambda> at 0x7fab23734160>})': Error starting action Jail('jellyfin')/iptables-allports: 'Script error'
Comme on peut le voir, f2b a des erreurs. Mais je ne suis pas sûr de savoir quelle direction prendre pour régler ces problèmes.
J'ai l'impression qu'il s'agit de problème lié à synology, et non swag, mais je peux me tromper.

Avez-vous des pistes ?

Merci encore
 
Code:
     1  2023-02-02 21:24:21,068 fail2ban.actions        [1447]: NOTICE  [nginx-unauthorized] Ban 146.70.134.149
     2  2023-02-02 21:24:21,085 fail2ban.utils          [1447]: ERROR   7fab232f4510 -- exec: iptables -w -N f2b-nginx-unauthorized
     3  iptables -w -A f2b-nginx-unauthorized -j RETURN
     4  iptables -w -I DOCKER-USER -p tcp -j f2b-nginx-unauthorized
     5  2023-02-02 21:24:21,085 fail2ban.utils          [1447]: ERROR   7fab232f4510 -- stderr: 'iptables: Chain already exists.'
     6  2023-02-02 21:24:21,085 fail2ban.utils          [1447]: ERROR   7fab232f4510 -- stderr: 'iptables: No chain/target/match by that name.'
     7  2023-02-02 21:24:21,085 fail2ban.utils          [1447]: ERROR   7fab232f4510 -- returned 1
     8  2023-02-02 21:24:21,086 fail2ban.actions        [1447]: ERROR   Failed to execute ban jail 'nginx-unauthorized' action 'iptables-allports' info 'ActionInfo({'ip': '146.70.134.149', 'family': 'inet4', 'fid': <function Actions.ActionInfo.<lambda> at 0x7fab23733a60>, 'raw-ticket': <function Actions.ActionInfo.<lambda> at 0x7fab23734160>})': Error starting action Jail('nginx-unauthorized')/iptables-allports: 'Script error'

En prenant un extrait de l'historique de Fail2Ban que tu as posté, l'erreur provient (à mon avis car je n'utilise pas iptables(8); les serveurs que je gère ayant Fail2Ban sont sur des *BSD donc ipf(8) et ipfw(8)) dans la première action de bannissement utilisée pour iptables(8), entraînant de facto un code d'erreur de sortie égal à 1 (ligne #7).
  • Ligne #2 : Fail2Ban demande de bannir un hôte avec iptables -w -N f2b-nginx-unauthorized
Hors l'option -N d'iptables(8) interdit la création d'une "chaîne" portant le même nom qu'une chaîne déjà existante comme l'indique la ligne #5 de l'extrait de l'historique ci-dessus.

CF. man 8 iptables sur une distribution GNU/Linux :

Code:
-N, --new-chain chain
       Create a new user-defined chain by the given name.
       There must be no target of that name already.

Il faut donc revoir les commandes iptables(8) de l'action iptables-allports et le filtre nginx-unauthorized.

Sur le wiki de Fail2Ban il y a également une note sur l'utilisation conjointe de docker.
 
En ce qui me concerne, je n’ai jamais eu besoin de modifier ces commandes, les seules modifications sont celles que j’ai postées.
 
En ce qui me concerne, je n’ai jamais eu besoin de modifier ces commandes, les seules modifications sont celles que j’ai postées.

En ayant regardé ce qu'était Swag, ça m'a tout l'air d'être plug'n'play donc ça ne me paraît pas normal d'avoir à modifier la configuration inhérentes aux filtres et actions de Fail2Ban par l'utilisateur. N'utilisant ni Swag et iptables, je ne peux en dire plus malheureusement.

Heureusement l'utilisation d'ipfw/ipf par Fail2Ban est plus simple qu'avec iptables (avec quelques modifications personnelles par rapport à l'action par défaut) :

Diff:
--- bsd-ipfw.local
+++ (clipboard)
@@ -14,7 +14,10 @@
 # Notes.:  command executed on demand at the first ban (or at the start of Fail2Ban if actionstart_on_demand is set to false).
 # Values:  CMD
 #
-actionstart = ipfw show | fgrep -c -m 1 -s 'table(<table>)' > /dev/null 2>&1 || ( ipfw show | awk 'BEGIN { b = <lowest_rule_num> } { if ($1 < b) {} else if ($1 == b) { b = $1 + 1 } else { e = b } } END { if (e) exit e <br> else exit b }'; num=$?; ipfw -q add $num <blocktype> <block> from table\(<table>\) to me <port>; echo $num > "<startstatefile>" )
+actionstart = ipfw show | fgrep -c -m 1 -s 'table(<table>)' > /dev/null 2>&1 || (
+    num=$(ipfw show | awk 'BEGIN { b = <lowest_rule_num> } { if ($1 == b) { b = $1 + 1 } } END { print b }');
+    ipfw -q add "$num" <blocktype> <block> from table\(<table>\) to me <port>; echo "$num" > "<startstatefile>"
+  )
 
 
 # Option:  actionstop
@@ -80,10 +83,12 @@
 #          ACTION defination at the top of man ipfw for allowed values.
 # Values:  STRING
 #
-blocktype = deny
+blocktype = unreach port
 
 # Option:  lowest_rule_num
 # Notes:   When fail2ban starts with action and there is no rule for the given table yet
 #          then fail2ban will start looking for an empty slot starting with this rule number.
 # Values:  NUM
-lowest_rule_num = 3
+lowest_rule_num = 111
+
+
 
En ayant regardé ce qu'était Swag, ça m'a tout l'air d'être plug'n'play donc ça ne me paraît pas normal d'avoir à modifier la configuration inhérentes aux filtres et actions de Fail2Ban par l'utilisateur. N'utilisant ni Swag et iptables, je ne peux en dire plus malheureusement.
Alors attention moi je parle de cette version de fail2ban :

Je n’utilise pas la version intégrée à swag car je ne sais pas configurer l’envoi d’email de notification. Et j’aime pas le fonctionnement des jails car un machine-jail.local ne fonctionne pas , il faut tout mettre dans le jail.conf.
 
Alors attention moi je parle de cette version de fail2ban :


Effectivement, depuis Fail2Ban 0.11.x, l'envoi de courriel à l'opérateur système doit être adaptée suivant le MSA (Mail Submission Agent) utilisé (sendmail, postfix, exim, qmail, etc.) ;)

Je n’utilise pas la version intégrée à swag car je ne sais pas configurer l’envoi d’email de notification. Et j’aime pas le fonctionnement des jails car un machine-jail.local ne fonctionne pas , il faut tout mettre dans le jail.conf.

Alors ceci n'est pas normal car par défaut (en tout cas avec un Fail2Ban installé en standalone) tout fichier *.local est pris et chargé.
 
Effectivement, depuis Fail2Ban 0.11.x, l'envoi de courriel à l'opérateur système doit être adaptée suivant le MSA (Mail Submission Agent) utilisé (sendmail, postfix, exim, qmail, etc.) ;)
Je n’ai pas tout saisi 😅
Cette image que j’utilise peut avoir en variable d’environnement les paramètres smtp de mon adresse mail, chose qui n’est pas possible avec le F2B intégré à swag.
Alors ceci n'est pas normal car par défaut (en tout cas avec un Fail2Ban installé en standalone) tout fichier *.local est pris et chargé.
Tout à fait d’accord avec toi, c’est ce qui m’a poussé à abandonner le F2B de swag.
 
Je n’ai pas tout saisi 😅

Un MSA (Mail Submission Agent) est un serveur assurant le relai d'un courriel soumis par un hôte (généralement authentifié).
Le rôle de MSA est assuré par la majorité de serveurs de messagerie électronique tels que ceux cités précédemment.

Pour l'expliquer plus simplement, lorsque l'on envoie un courriel, on contacte le serveur SMTP de son prestataire de messagerie pour envoyer (relayer dans le jargon des postmasters) afin qu'il soit distribué au(x) destinataire(s).

Tout à fait d’accord avec toi, c’est ce qui m’a poussé à abandonner le F2B de swag.

La configuration de Fail2Ban étant modifiée à chaque mise à jour, il faut vraiment apporter ses modifications personnelles dans les fichiers *.local
 
Les actions/filtres déterminent le comportement par le biais de commandes shell permettant de définir des conditions pour bannir ou non un hôte.
Dans votre cas, Fail2Ban fait appel à iptables(8) (le pare-feu sur une distribution GNU/Linux dont DSM en est une) pour l'action de bannir ou non et aux expressions régulières pour la définition.
 
Bonjour,
Personnellement je n'ai jamais réussi à faire fonctionner fail2ban en docker/swag sans macvlan.
les IP externe ne sont pas transmis à swag sans macvlan.
 
  • J'aime
Réactions: MilesTEG
Je viens de me rendre compte que mon Fail2Ban (image CrazyMax) bannait bien les IP, mais elles ne sont pas vraiment bloquée dans le NAS... Donc le service reste accessible.
 
Bon j'ai tenté diverses choses...
chain = FORWARD ou chain = DOCKER-USER
Et peut-importe, les IP bannies ne sont pas réellement bloquées par le parefeu du NAS...
La commande suivante sudo iptables -S | grep f2b me retourne pourtant bien des règles, mais il n'y a pas de DROP derrière... ni même d'adresse IP, ce qui je pense est le résultat du non blocage... (bon après, je ne sais pas interpréter ce que renvoie cette commande) :
1676028048793.png

Reste maintenant à trouver comment ajouter ça :)

@hydrogenation_moskito Tu pourrais lancer cette commande en SSH ?
Bash:
sudo iptables -S | grep f2b
Et coller ce que ça te retourne ? (après avoir fait un test de bannissement depuis une IP en 4G par exemple).

PS : si ton soucis s'avère identique au miens, je laisserais mon message ici, sinon je créerai un nouveau sujet :)
 
J'ai réussi à avoir le DROP et l'IP dans la règle : suivre ceci : https://github.com/sosandroid/docker-fail2ban-synology/issues/6

Mais depuis cette adresse IP je continue à pouvoir accéder au service... Là en l'occurence, c'est gitea.

1676029188240.png
Je tente avec Calibre-Web :
1676029308724.png

Même chose. Je suis convaincu que ce problème est apparu avec une MAJ de DSM récente... je ne sais pas quand, mais je sais qu'avec mes réglages, ça bannait correctement les IP avant, et je ne pouvais accéder à plus rien sur le NAS depuis l'IP bannie...
Là, tout continue de fonctionner...
 
Bonsoir,

Premièrement, désolé de mon inactivité. Après mon dernier message, j'ai un peu baissé les bras et, étrangement, je n'ai jamais reçu d'emails m'indiquant que de nouveaux messages avaient été postés sur ce thread. Étrange...

Mais il y a quelques jours, frustrés de mon abandon, j'ai repris de zéro et ai voulu commencer avec cette-fois ci non pas swag mais avec le fail2ban de crazy-max.
Aidé de sa documentation ainsi que du wiki très bien rédigé de vaultwarden, je suis tombé sans le vouloir sur le même repo que toi, @MilesTEG1 ! À savoir, https://github.com/sosandroid/docker-fail2ban-synology

En suivant les instructions du setup de fail2ban sur le wiki de vaultwarden, j'ai finalement réussi à bannir des IPs !
Il m'a suffit d'adapter mon container swag et ses fichiers de conf, et mon container swag a finalement accepter de bloquer les IPs qui brute-forcent.

Je récapitule donc les changements dont j'ai du procéder:
- En tout premier lieu, permettre à son syno d'accéder aux réelles adresses IPs en suivant ce guide, comme je l'avais mentionné dans mon premier message. Je précise que mes modifications dans les jails de `chain = DOCKER-USER` que je mentionne dans mon tout premier message s'avèrent inutiles.
- Je présie aussi que le changement de l'action en `action = %(action_mwl)s` que je mentionne quelques messages plus tard est aussi inutile. Dans ce même message, je me rends compte maintenant que j'avais toutes les clés en main, mais apparemment cela ne m'a pas suffit:
Il faut impérativement configurer son blocktype en DROP, comme l'explique toujours ce même repo: https://github.com/sosandroid/docker-fail2ban-synology
Il faut donc créer un fichier .local qui overridera. Tout est expliqué sur le repo github.
Les fichiers ".local" sont donc à créer, comme l'a expliqué @cooper quelques messages plus loin.


@hydrogenation_moskito Tu pourrais lancer cette commande en SSH ?
Bash:
Bash:
sudo iptables -S | grep f2b
Et coller ce que ça te retourne ? (après avoir fait un test de bannissement depuis une IP en 4G par exemple).
Voici mon output:
Bash:
-N f2b-vaultwarden
-A FORWARD -j f2b-vaultwarden
Je n'ai pas de "DROP derrière", comme tu dis. Étrangement, même si j'ai fait cette commande juste après m'être fait ban après avoir "brute-force" le login de mon service Jellyfin, rien n'apparait à ce propos, seulement ce "f2b-vaultwarden", qui fait référence à mon ancien containeur, qui ne tourne plus maintenant. Pourtant, je suis bel et bien ban IP, donc f2b fonctionne dorénavant.
 
  • J'aime
Réactions: cooper