Score:0

Fail2ban on CentOS 7 with Docker-powered Traefik ban OK without iptables rule addition

fr flag

I set up a Traefik instance run by Docker engine in Swarm mode with a "classical" configuration (see below, for sake of brevity I only put relevant [to me] parts. Feel free to ask more details if you need so).

Fail2Ban is installed, as well as firewalld (CentOS distribution). So far I put simple filter/jail configuration, mostly for blocking DOS and bruteforce, by watching Traefik access log.

My problem : when I try with Nikto or Hydra, I can see my trying IP been blacklisted :

# fail2ban-client status symfony-auth
Status for the jail: symfony-auth
|- Filter
|  |- Currently failed: 3
|  |- Total failed:     906
|  `- File list:        /var/log/traefik/access.log
`- Actions
   |- Currently banned: 1
   |- Total banned:     2
   `- Banned IP list:   37.19.218.169

But nothing changes on iptables rules part, and I can see the given IP is not blocked. Furthermore, if I try to navigate on website from the banned IP, I can do it, even though it is banned.

I must add that I have 00-firewalld.conf file, with default instructions regarding to actions for this distro:

# cat /etc/fail2ban/jail.d/00-firewalld.conf
# This file is part of the fail2ban-firewalld package to configure the use of
# the firewalld actions as the default actions.  You can remove this package
# (along with the empty fail2ban meta-package) if you do not use firewalld
[DEFAULT]
banaction = firewallcmd-rich-rules[actiontype=<multiport>]
banaction_allports = firewallcmd-rich-rules[actiontype=<allports>]
backend=systemd

Finally, I don't have any time difference, such as stated here.

# tail /var/log/messages
Jul 12 13:28:05 ....
# timedatectl
               Local time: Mon 2021-07-12 13:30:18 UTC
           Universal time: Mon 2021-07-12 13:30:18 UTC
                 RTC time: Mon 2021-07-12 13:30:13
                Time zone: UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no


So why my banned IP can still reach the target website ? Thanks for yours leads & enlightments.

Snippets

Traefik docker-compose.yml

Logging part

version: "3.3"

services:
  reverse-proxy:
    image: "traefik:v2.4"
    command:
      # Log configuration
      #- "--log.level=DEBUG"
      - "--log.filepath=/var/log/traefik/traefik.log"
      - "--accesslog.filepath=/var/log/traefik/access.log"
     

Volume part :

    # ...
    volumes:
      # To persist certificates
      - traefik-certificates:/letsencrypt
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - /var/log/traefik:/var/log/traefik/
    # ...

Fail2Ban

My filter

/etc/fail2ban/filter.d/my_filter.conf

[Definition]
failregex = ^<HOST>.*"(GET|POST|HEAD).*" (404|444|403|400|301) .*$
ignoreregex =

My jail

[my_jail]
 enabled  = true
 port     = http,https
 filter   = my_filter
 logpath  = /var/log/traefik/access.log
 maxretry = 10

Client status

# fail2ban-client status
Status
|- Number of jail:      2
`- Jail list:   sshd, my_jail
Score:1
il flag

So why my banned IP can still reach the target website?

There may be 3 reasons for that:

  1. your firewalld backend (iptables?) is unsuitable to handle this, see https://github.com/fail2ban/fail2ban/issues/1609#issuecomment-303085942 (or https://github.com/firewalld/firewalld/issues/44#issuecomment-408211978) for details. Shortly, new nftables backend of firewalld can handle this properly, so you may need to switch to this, or ...
    This may also lead us to next two reasons (former is more related than the later):

  2. if your network sub-system has some white-listing rules (and I guess so), for instance conntrack rules bypassing already established connections before the chains of fail2ban, then adding the rules to fail2ban tables, rejecting the IP, would not affect this established connections (e. g. in case of keep-alive), only new connections will be rejected then... in this case either ensure to reject connection in web-server after auth-failures, or reorder the chains (chains of fail2ban before the white-listing rules), or kill the connection with extra command in actionban, e.g. ss -K dst "[<ip>]" or conntrack -D -s <ip>, etc. See https://github.com/fail2ban/fail2ban/pull/3018/commits/8f6a8df3a45395620e434fd15b4ede694a1d00aa (or https://github.com/fail2ban/fail2ban/commit/bbfff1828061514e48395a5dbc5c1f9f81625e82) for similar issue with ufw;

  3. because it is dockerized, you have probably to define chain = DOCKER-USER or similar, just action firewallcmd-rich-rules is not suitable for that (don't have parameter chain at all)... Use another banning action (e.g. native net-filters like iptables/ipset or nftables) supporting that.

Anyway you have to check how the incoming traffic (inclusive established) reaches the resulting chains/tables fail2ban creates for the banning of IP, considering all pre-defined chains/tables of docker and firewalld.
Alternatively simply use banning actions for native net-filter sub-systems like iptables+ipset or nftables (e. g. with proper target table for the fail2ban chains, for instance DOCKER-USER instead of INPUT).

fr flag
Thanks for your remarkably detailled answer. The point was indeed your third one, I totally missd out the multiple chains regarding Iptables. Adding `chain = DOCKER-USER` made it work without any problem
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.