tomMoulard / fail2ban

Traefik plugin on fail2ban middleware

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

All traffic banned

jsmue opened this issue · comments

I think I'm dealing with a bug because I've checked all the settings and the plugin generally behaves as described. Unfortunately, my traffic is being blocked and I can't find a reason why.

I am using the latest plugin version (0.7.1) with the latest Traefik version (2.10.5). I use Docker as a provider.

For my tests I use the Traefik dashboard, which I have secured with Simle Auth. Additional brute forcing protection would be a welcome addition.

In my setup, I first tried to lock myself out by entering the wrong credentials: that worked straight away. Since then - I tested this two weeks ago - I have no longer been able to authenticate myself successfully. I am always blocked with the status '403'. What I have tried:

  • Change the order of the middlewares: No influence
  • Put my IP on the whilelist: Works, I get through. However, this is not a good solution for dynamic IPs.
  • Set Allow rules for certain paths: Works, but undermines brute forcing protection.

What I am missing is a way to check on the banned IP adresses. Is there a way to find out, what's happening?
Thanks!

Here is an excerpt from my traefik_dynamic.yaml (for completeness):

    my-fail2ban:
      plugin:
        fail2ban:
          rules:
            bantime: "3h"
            enabled: true
            findtime: "10m"
            maxretry: 4
          whitelist:
            ip:
              - "::1"
              - "127.0.0.1"
  routers:
    api:
      rule: Host(`dashboard.mydomain.com`)
      entrypoints:
        - websecure
      middlewares:
        - simpleAuth
        - my-fail2ban
      service: api@internal
      tls:
        certResolver: lets-encrypt

Hello @jsmue,

Thanks for your interest in this Traefik Plugin!

This Plugin does not know know any information about how Traefik will handle your request afterwards, or before entering the plugin mechanism. Therefore, it cannot know that you have locked yourself out by entering wrong credentials.

Could you try again, but without the simpleAuth middleware?

Hi @tomMoulard,

i've just checked. Disabling simpleAuth doesn't change the behavior. In my access logs the page view creates about 45 lines. First I have a status 302, then 200:

{"ClientAddr":"92.xxx.xxx.xx:59696","ClientHost":"92.xxx.xxx.xx","ClientPort":"59696","ClientUsername":"-","DownstreamContentSize":34,"DownstreamStatus":302,"Duration":386159,"GzipRatio":0,"OriginContentSize":0,"OriginDuration":0,"OriginStatus":0,"Overhead":386159,"RequestAddr":"traefik.mydomain.com","RequestContentSize":0,"RequestCount":6795,"RequestHost":"traefik.mydomain.com","RequestMethod":"GET","RequestPath":"/","RequestPort":"-","RequestProtocol":"HTTP/2.0","RequestScheme":"https","RetryAttempts":0,"RouterName":"api@file","StartLocal":"2023-11-07T18:51:44.26804881+01:00","StartUTC":"2023-11-07T17:51:44.26804881Z","TLSCipher":"TLS_CHACHA20_POLY1305_SHA256","TLSVersion":"1.3","entryPointName":"websecure","level":"info","msg":"","request_User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","time":"2023-11-07T18:51:44+01:00"}
{"ClientAddr":"92.xxx.xxx.xx:59696","ClientHost":"92.xxx.xxx.xx","ClientPort":"59696","ClientUsername":"-","DownstreamContentSize":3124,"DownstreamStatus":200,"Duration":773618,"GzipRatio":0,"OriginContentSize":0,"OriginDuration":0,"OriginStatus":0,"Overhead":773618,"RequestAddr":"traefik.mydomain.com","RequestContentSize":0,"RequestCount":6796,"RequestHost":"traefik.mydomain.com","RequestMethod":"GET","RequestPath":"/dashboard/","RequestPort":"-","RequestProtocol":"HTTP/2.0","RequestScheme":"https","RetryAttempts":0,"RouterName":"api@file","StartLocal":"2023-11-07T18:51:44.276384115+01:00","StartUTC":"2023-11-07T17:51:44.276384115Z","TLSCipher":"TLS_CHACHA20_POLY1305_SHA256","TLSVersion":"1.3","entryPointName":"websecure","level":"info","msg":"","request_User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","time":"2023-11-07T18:51:44+01:00"}

Then I have more than 40 lines with status 403; they all look pretty similar, for example like this:

{"ClientAddr":"92.xxx.xxx.xx:59696","ClientHost":"92.xxx.xxx.xx","ClientPort":"59696","ClientUsername":"-","DownstreamContentSize":0,"DownstreamStatus":403,"Duration":540676,"OriginContentSize":0,"OriginDuration":0,"OriginStatus":0,"Overhead":540676,"RequestAddr":"traefik.mydomain.com","RequestContentSize":0,"RequestCount":6798,"RequestHost":"traefik.mydomain.com","RequestMethod":"GET","RequestPath":"/dashboard/js/app.ccc19229.js","RequestPort":"-","RequestProtocol":"HTTP/2.0","RequestScheme":"https","RetryAttempts":0,"RouterName":"api@file","StartLocal":"2023-11-07T18:51:44.428084327+01:00","StartUTC":"2023-11-07T17:51:44.428084327Z","TLSCipher":"TLS_CHACHA20_POLY1305_SHA256","TLSVersion":"1.3","entryPointName":"websecure","level":"info","msg":"","request_User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","time":"2023-11-07T18:51:44+01:00"}

I am sorry, but I cannot reproduce your issue. I've tried using your dynamic configuration, but with not luck.
Can you reproduce your issue using my configuration ?

My docker-compose reproduction case

Using this as a base, here is my configuration:

Please note that I experience no difference in both fail2ban@file and fail2ban-registery@docker middlewares.

# docker-compose.yml
version: '3.9'

services:
  traefik:
    image: traefik:v3.0
    command:
      - --api.insecure=true
      - --providers.docker
      - --log.level=DEBUG
      - --providers.file.filename=/tmp/traefik.yml
      # - --experimental.localPlugins.fail2ban-local.moduleName=github.com/tomMoulard/fail2ban
      - --experimental.plugins.fail2ban-registery.modulename=github.com/tomMoulard/fail2ban
      - --experimental.plugins.fail2ban-registery.version=v0.7.1
    ports:
      - 80:80
      - 8080:8080
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik.yml:/tmp/traefik.yml
      # - .:/plugins-local/src/github.com/tomMoulard/fail2ban/
    tty: true

  whoami:
    image: traefik/whoami # https://github.com/traefik/whoami
    command: -name whoami
    labels:
      # traefik.http.routers.fail2ban-local.rule: Host(`fail2ban-local.localhost`)
      # traefik.http.routers.fail2ban-local.middlewares: fail2ban-local
      # traefik.http.middlewares.fail2ban-local.plugin.fail2ban-local.rules.enabled: true
      # traefik.http.middlewares.fail2ban-local.plugin.fail2ban-local.rules.bantime: 3h
      # traefik.http.middlewares.fail2ban-local.plugin.fail2ban-local.rules.findtime: 10m
      # traefik.http.middlewares.fail2ban-local.plugin.fail2ban-local.rules.maxretry: 4
      # traefik.http.middlewares.fail2ban-local.plugin.fail2ban-local.whitelist.ip: 127.0.0.2,::1
      # traefik.http.middlewares.fail2ban-local.plugin.fail2ban-local.blacklist.ip: 127.0.0.3
      # traefik.http.middlewares.fail2ban-local.plugin.fail2ban-local.rules.urlregexps[0].regexp: /no
      # traefik.http.middlewares.fail2ban-local.plugin.fail2ban-local.rules.urlregexps[0].mode: block
      # traefik.http.middlewares.fail2ban-local.plugin.fail2ban-local.rules.urlregexps[1].regexp: /yes
      # traefik.http.middlewares.fail2ban-local.plugin.fail2ban-local.rules.urlregexps[1].mode: allow

      traefik.http.routers.fail2ban-registery.rule: Host(`fail2ban-registery.localhost`)
      traefik.http.routers.fail2ban-registery.middlewares: fail2ban-registery
      traefik.http.middlewares.fail2ban-registery.plugin.fail2ban-registery.rules.enabled: true
      traefik.http.middlewares.fail2ban-registery.plugin.fail2ban-registery.rules.bantime: 3h
      traefik.http.middlewares.fail2ban-registery.plugin.fail2ban-registery.rules.findtime: 10m
      traefik.http.middlewares.fail2ban-registery.plugin.fail2ban-registery.rules.maxretry: 4
      traefik.http.middlewares.fail2ban-registery.plugin.fail2ban-registery.whitelist.ip: 127.0.0.2,::1

      traefik.http.routers.fail2ban-local.rule: Host(`fail2ban-local.localhost`)
      traefik.http.routers.fail2ban-local.middlewares: fail2ban@file
# ./traefik.yml
http:
  middlewares:
    fail2ban:
      plugin:
        fail2ban-registery:
          rules:
            bantime: "3h"
            enabled: true
            findtime: "10m"
            maxretry: 4
          whitelist:
            IP:
              - "::1"
              - "127.0.0.1"

Hi @tomMoulard,

I have investigated the issue further and have come to the interim conclusion that it is less a problem with the fail2ban middleware itself and more a problem with the traefik dashboard.
When I browse through the dashboard, I get numerous errors 400 in the console. I checked with fail2ban inactive. If activated, fail2ban blocks me immediately.

For example, when browsing individual tabs in the dashboard, the following path is requested (you can also add http and udp in your mind)

/api/tcp/routers?search=&status=&per_page=10&page=2

opening it in the browser returns: {"message":"invalid request: page: 2, per_page: 10"}. Since my instance has a manageable number of routers, there is no page 2 so far (even if there was, page 3 would probably be queried immediately).

I'm thinking about restricting access to this dashboard to a specific network anyway, so I can definitely use the middleware. No idea whether it makes sense to think about improvements to the middleware. If there is one point, it might be to be able to set the error codes it responds to.

Tanks for looking into this at least!

Oh ! Ok, I got why you have this error ! When showing the dashboard, your browser makes roughly 60 to 70 requests to show the UI, therefore it is making let's say 65 requests to your traefik service. The catch is that you configured the plugin to block any user that does more than 4 requests during a 10-min time window.
With this setting configured as is, the first 5 requests made by your browser were successful, but not the following ones.
Try changing this maxretry setting to 70, and you will be able to see the dashboard, but not to reload the page.

As this seems to be a configuration issue, I am closing this issue.

In case I'm wrong, feel free to re-open the issue.