5

This is my filter:

[Definition]
failregex = <HOST> .* "POST /customer/account/create.*$
            <HOST> .* "GET /customer/account/create.*$

and this the corresponding jail:

[magento-customer]
enabled = true
port    = http,https
logpath = /var/lib/docker/volumes/shop_example_com_nginx/_data/logs/shop.example.com-access.log
findtime = 5m
maxretry = 5
bantime = 1d
banaction = iptables-multiport[blocktype=DROP]
banaction_allports = iptables-allports[blocktype=DROP]

IP addresses seem to get banned:

2024-03-22 09:57:35,779 fail2ban.filter         [995808]: INFO    [magento-customer] Found 180.178.50.130 - 2024-03-22 09:57:35
2024-03-22 09:57:35,987 fail2ban.filter         [995808]: INFO    [magento-customer] Found 180.178.50.130 - 2024-03-22 09:57:35
2024-03-22 09:57:36,149 fail2ban.filter         [995808]: INFO    [magento-customer] Found 180.178.50.130 - 2024-03-22 09:57:36
2024-03-22 09:57:36,263 fail2ban.filter         [995808]: INFO    [magento-customer] Found 180.178.50.130 - 2024-03-22 09:57:36
2024-03-22 09:57:37,479 fail2ban.filter         [995808]: INFO    [magento-customer] Found 180.178.50.130 - 2024-03-22 09:57:37
2024-03-22 09:57:37,547 fail2ban.filter         [995808]: INFO    [magento-customer] Found 180.178.50.130 - 2024-03-22 09:57:37
2024-03-22 09:57:37,709 fail2ban.actions        [995808]: WARNING [magento-customer] 180.178.50.130 already banned

Resulting in this iptables entry:

iptables -L | grep -a "180.178.50.130"
DROP       all  --  180.178.50.130       anywhere

Nevertheless I constantly get entries by this IP in the nginx.log (timezones are the same on the host and in the docker container):

180.178.50.130 - - [22/Mar/2024:10:02:51 +0100] "POST /customer/account/createpost/ HTTP/1.1" 302 5 "https://shop.example.com/customer/account/create/" "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"
180.178.50.130 - - [22/Mar/2024:10:02:52 +0100] "POST /customer/account/createpost/ HTTP/1.1" 302 5 "https://shop.example.com/customer/account/create/" "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"
180.178.50.130 - - [22/Mar/2024:10:02:52 +0100] "GET /customer/account/create/ HTTP/1.1" 200 101026 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
180.178.50.130 - - [22/Mar/2024:10:02:53 +0100] "GET /customer/account/create/ HTTP/1.1" 200 101026 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"

As you can see from the logpath above, I'm running nginx in a docker container with ports 80 and 443 directly exposed to the host, no ingress/reverse proxy in use:

  nginx:
    […]
    ports:
      - target: 80
        published: 80
        mode: host
      - target: 443
        published: 443
        mode: host

fail2ban ver. 0.11.2 is installed directly on the host.

The server is the only node behind a failover gateway, which IP address is added to the network interface like this:

ip address add 116.x.y.z/32 dev enp6s0

Client IP addresses are being received by the server unaltered, and the same as in the nginx docker container.

Here is the full iptables-save output:

# iptables-save
# Generated by iptables-save v1.8.7 on Fri Mar 22 14:37:00 2024
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A OUTPUT -p udp -m udp --dport 4789 -m bpf --bytecode "7,32 0 0 4294963252,7 0 0 0,64 0 0 4,116 0 0 8,21 1 0 4097,6 0 0 0,6 0 0 4294967295" -j MARK --set-xmark 0xd0c4e3/0xffffffff
-A OUTPUT -p udp -m udp --dport 4789 -m bpf --bytecode "7,32 0 0 4294963252,7 0 0 0,64 0 0 4,116 0 0 8,21 1 0 4098,6 0 0 0,6 0 0 4294967295" -j MARK --set-xmark 0xd0c4e3/0xffffffff
-A OUTPUT -p udp -m udp --dport 4789 -m bpf --bytecode "7,32 0 0 4294963252,7 0 0 0,64 0 0 4,116 0 0 8,21 1 0 4101,6 0 0 0,6 0 0 4294967295" -j MARK --set-xmark 0xd0c4e3/0xffffffff
-A OUTPUT -p udp -m udp --dport 4789 -m bpf --bytecode "7,32 0 0 4294963252,7 0 0 0,64 0 0 4,116 0 0 8,21 1 0 4099,6 0 0 0,6 0 0 4294967295" -j MARK --set-xmark 0xd0c4e3/0xffffffff
COMMIT
# Completed on Fri Mar 22 14:37:00 2024
# Generated by iptables-save v1.8.7 on Fri Mar 22 14:37:00 2024
*filter
:INPUT DROP [631649:29166339]
:FORWARD DROP [87:4724]
:OUTPUT ACCEPT [34097:2318474]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
:f2b-magento-customer - [0:0]
:ufw-after-forward - [0:0]
:ufw-after-input - [0:0]
:ufw-after-logging-forward - [0:0]
:ufw-after-logging-input - [0:0]
:ufw-after-logging-output - [0:0]
:ufw-after-output - [0:0]
:ufw-before-forward - [0:0]
:ufw-before-input - [0:0]
:ufw-before-logging-forward - [0:0]
:ufw-before-logging-input - [0:0]
:ufw-before-logging-output - [0:0]
:ufw-before-output - [0:0]
:ufw-logging-allow - [0:0]
:ufw-logging-deny - [0:0]
:ufw-not-local - [0:0]
:ufw-reject-forward - [0:0]
:ufw-reject-input - [0:0]
:ufw-reject-output - [0:0]
:ufw-skip-to-policy-forward - [0:0]
:ufw-skip-to-policy-input - [0:0]
:ufw-skip-to-policy-output - [0:0]
:ufw-track-forward - [0:0]
:ufw-track-input - [0:0]
:ufw-track-output - [0:0]
:ufw-user-forward - [0:0]
:ufw-user-input - [0:0]
:ufw-user-limit - [0:0]
:ufw-user-limit-accept - [0:0]
:ufw-user-logging-forward - [0:0]
:ufw-user-logging-input - [0:0]
:ufw-user-logging-output - [0:0]
:ufw-user-output - [0:0]
-A INPUT -p tcp -m multiport --dports 80,443 -j f2b-magento-customer
-A INPUT -p udp -m policy --dir in --pol none -m udp --dport 4789 -m bpf --bytecode "7,32 0 0 4294963252,7 0 0 0,64 0 0 4,116 0 0 8,21 1 0 4099,6 0 0 0,6 0 0 4294967295" -j DROP
-A INPUT -p udp -m policy --dir in --pol none -m udp --dport 4789 -m bpf --bytecode "7,32 0 0 4294963252,7 0 0 0,64 0 0 4,116 0 0 8,21 1 0 4101,6 0 0 0,6 0 0 4294967295" -j DROP
-A INPUT -p udp -m policy --dir in --pol none -m udp --dport 4789 -m bpf --bytecode "7,32 0 0 4294963252,7 0 0 0,64 0 0 4,116 0 0 8,21 1 0 4098,6 0 0 0,6 0 0 4294967295" -j DROP
-A INPUT -p udp -m policy --dir in --pol none -m udp --dport 4789 -m bpf --bytecode "7,32 0 0 4294963252,7 0 0 0,64 0 0 4,116 0 0 8,21 1 0 4097,6 0 0 0,6 0 0 4294967295" -j DROP
-A INPUT -j ufw-before-logging-input
-A INPUT -j ufw-before-input
-A INPUT -j ufw-after-input
-A INPUT -j ufw-after-logging-input
-A INPUT -j ufw-reject-input
-A INPUT -j ufw-track-input
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A FORWARD -o docker_gwbridge -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker_gwbridge -j DOCKER
-A FORWARD -i docker_gwbridge ! -o docker_gwbridge -j ACCEPT
-A FORWARD -j ufw-before-logging-forward
-A FORWARD -j ufw-before-forward
-A FORWARD -j ufw-after-forward
-A FORWARD -j ufw-after-logging-forward
-A FORWARD -j ufw-reject-forward
-A FORWARD -j ufw-track-forward
-A FORWARD -i docker_gwbridge -o docker_gwbridge -j DROP
-A OUTPUT -j ufw-before-logging-output
-A OUTPUT -j ufw-before-output
-A OUTPUT -j ufw-after-output
-A OUTPUT -j ufw-after-logging-output
-A OUTPUT -j ufw-reject-output
-A OUTPUT -j ufw-track-output
-A DOCKER -d 172.18.0.7/32 ! -i docker_gwbridge -o docker_gwbridge -p tcp -m tcp --dport 443 -j ACCEPT
-A DOCKER -d 172.18.0.7/32 ! -i docker_gwbridge -o docker_gwbridge -p tcp -m tcp --dport 80 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -i docker_gwbridge ! -o docker_gwbridge -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o docker_gwbridge -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
-A f2b-magento-customer -s 103.242.14.161/32 -j DROP
-A f2b-magento-customer -s 103.242.14.156/32 -j DROP
-A f2b-magento-customer -s 103.242.14.239/32 -j DROP
-A f2b-magento-customer -s 103.242.14.222/32 -j DROP
-A f2b-magento-customer -s 154.12.26.174/32 -j DROP
-A f2b-magento-customer -s 154.12.84.126/32 -j DROP
-A f2b-magento-customer -s 154.12.26.164/32 -j DROP
-A f2b-magento-customer -s 154.12.84.68/32 -j DROP
-A f2b-magento-customer -s 103.116.247.155/32 -j DROP
-A f2b-magento-customer -s 103.108.67.209/32 -j DROP
-A f2b-magento-customer -s 154.12.23.218/32 -j DROP
-A f2b-magento-customer -s 52.128.224.138/32 -j DROP
-A f2b-magento-customer -s 148.66.23.226/32 -j DROP
-A f2b-magento-customer -s 182.16.79.226/32 -j DROP
-A f2b-magento-customer -s 182.16.20.194/32 -j DROP
-A f2b-magento-customer -s 180.178.45.18/32 -j DROP
-A f2b-magento-customer -s 52.128.224.146/32 -j DROP
-A f2b-magento-customer -s 182.16.82.146/32 -j DROP
-A f2b-magento-customer -s 148.66.23.58/32 -j DROP
-A f2b-magento-customer -s 148.66.23.42/32 -j DROP
-A f2b-magento-customer -s 182.16.9.186/32 -j DROP
-A f2b-magento-customer -s 111.68.6.66/32 -j DROP
-A f2b-magento-customer -s 111.68.10.170/32 -j DROP
-A f2b-magento-customer -s 112.121.165.90/32 -j DROP
-A f2b-magento-customer -s 216.118.233.234/32 -j DROP
-A f2b-magento-customer -s 112.121.165.34/32 -j DROP
-A f2b-magento-customer -s 180.178.44.242/32 -j DROP
-A f2b-magento-customer -s 180.178.50.130/32 -j DROP
-A f2b-magento-customer -s 182.16.44.42/32 -j DROP
-A f2b-magento-customer -s 52.128.230.50/32 -j DROP
-A f2b-magento-customer -s 52.128.247.66/32 -j DROP
-A f2b-magento-customer -s 112.121.172.98/32 -j DROP
-A f2b-magento-customer -s 148.66.20.122/32 -j DROP
-A f2b-magento-customer -s 154.12.93.254/32 -j DROP
-A f2b-magento-customer -j RETURN
-A ufw-after-input -p udp -m udp --dport 137 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp -m udp --dport 138 -j ufw-skip-to-policy-input
-A ufw-after-input -p tcp -m tcp --dport 139 -j ufw-skip-to-policy-input
-A ufw-after-input -p tcp -m tcp --dport 445 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp -m udp --dport 67 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp -m udp --dport 68 -j ufw-skip-to-policy-input
-A ufw-after-input -m addrtype --dst-type BROADCAST -j ufw-skip-to-policy-input
-A ufw-after-logging-forward -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW BLOCK] "
-A ufw-after-logging-input -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW BLOCK] "
-A ufw-before-forward -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-forward -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A ufw-before-forward -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A ufw-before-forward -p icmp -m icmp --icmp-type 12 -j ACCEPT
-A ufw-before-forward -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A ufw-before-forward -j ufw-user-forward
-A ufw-before-input -i lo -j ACCEPT
-A ufw-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-input -m conntrack --ctstate INVALID -j ufw-logging-deny
-A ufw-before-input -m conntrack --ctstate INVALID -j DROP
-A ufw-before-input -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A ufw-before-input -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A ufw-before-input -p icmp -m icmp --icmp-type 12 -j ACCEPT
-A ufw-before-input -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A ufw-before-input -p udp -m udp --sport 67 --dport 68 -j ACCEPT
-A ufw-before-input -j ufw-not-local
-A ufw-before-input -d 224.0.0.251/32 -p udp -m udp --dport 5353 -j ACCEPT
-A ufw-before-input -d 239.255.255.250/32 -p udp -m udp --dport 1900 -j ACCEPT
-A ufw-before-input -j ufw-user-input
-A ufw-before-output -o lo -j ACCEPT
-A ufw-before-output -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-output -j ufw-user-output
-A ufw-logging-allow -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW ALLOW] "
-A ufw-logging-deny -m conntrack --ctstate INVALID -m limit --limit 3/min --limit-burst 10 -j RETURN
-A ufw-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW BLOCK] "
-A ufw-not-local -m addrtype --dst-type LOCAL -j RETURN
-A ufw-not-local -m addrtype --dst-type MULTICAST -j RETURN
-A ufw-not-local -m addrtype --dst-type BROADCAST -j RETURN
-A ufw-not-local -m limit --limit 3/min --limit-burst 10 -j ufw-logging-deny
-A ufw-not-local -j DROP
-A ufw-skip-to-policy-forward -j DROP
-A ufw-skip-to-policy-input -j DROP
-A ufw-skip-to-policy-output -j ACCEPT
-A ufw-track-output -p tcp -m conntrack --ctstate NEW -j ACCEPT
-A ufw-track-output -p udp -m conntrack --ctstate NEW -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 32 -j ACCEPT
-A ufw-user-input -p udp -m udp --dport 32 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 80 -j ACCEPT
-A ufw-user-input -p tcp -m tcp --dport 443 -j ACCEPT
-A ufw-user-input -p udp -m udp --dport 443 -j ACCEPT
-A ufw-user-input -s 78.46.38.201/32 -p tcp -m tcp --dport 5666 -j ACCEPT
-A ufw-user-input -s 78.46.38.201/32 -p udp -m udp --dport 5666 -j ACCEPT
-A ufw-user-limit -m limit --limit 3/min -j LOG --log-prefix "[UFW LIMIT BLOCK] "
-A ufw-user-limit -j REJECT --reject-with icmp-port-unreachable
-A ufw-user-limit-accept -j ACCEPT
COMMIT
# Completed on Fri Mar 22 14:37:00 2024
# Generated by iptables-save v1.8.7 on Fri Mar 22 14:37:00 2024
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o docker_gwbridge -j MASQUERADE
-A POSTROUTING -s 172.18.0.7/32 -d 172.18.0.7/32 -p tcp -m tcp --dport 443 -j MASQUERADE
-A POSTROUTING -s 172.18.0.7/32 -d 172.18.0.7/32 -p tcp -m tcp --dport 80 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
-A DOCKER -i docker_gwbridge -j RETURN
-A DOCKER ! -i docker_gwbridge -p tcp -m tcp --dport 443 -j DNAT --to-destination 172.18.0.7:443
-A DOCKER ! -i docker_gwbridge -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.18.0.7:80
COMMIT
# Completed on Fri Mar 22 14:37:00 2024

What do I have to do to get IP addresses banned? Shouldn't this already happen when the address is being DROPped by iptables on the host?

3
  • 1
    Show the full iptables-save output.
    – AlexD
    Commented Mar 22 at 12:19
  • 1
    @AlexD, thanks, I added it!
    – digijay
    Commented Mar 22 at 13:42
  • In the end all I had to add to my jail was chain = DOCKER-USER. Thanks @AlexD!
    – digijay
    Commented Mar 25 at 15:35

3 Answers 3

12

Docker networking is set up in such a way that it bypasses normal iptables chains. fail2ban uses INPUT chain but to filter docker traffic you need to use its custom DOCKER-USER chain. See the documentation

7
  • 1
    There's a reason I set "iptables": false for every Docker I manage.
    – iBug
    Commented Mar 23 at 2:14
  • 1
    @iBug: Doesn't it come with another set of problems? Commented Mar 23 at 22:34
  • @EricDuminil If you're a seasoned table manager, chances are you'll find more troubles with "iptables": true, especially when trying to integrate more iptables-related stuff (like the aforementioned f2b).
    – iBug
    Commented Mar 24 at 5:47
  • 1
    @iBug: Thanks. I'm still looking for a satisfying solution. I find it really weak that docker simply bypasses UFW rules without warnings. But it's also pretty convenient to find services by their names in docker networks. In the meantime, I leave iptables true, set up an external Firewall, and add some UFW after rules. Commented Mar 24 at 13:33
  • 1
    In the end all I had to add to my jail was chain = DOCKER-USER. Thanks, @AlexD!
    – digijay
    Commented Mar 25 at 15:34
3

Agreed this is a little odd.

I'm assuming that you know the client connections are coming from these addresses (i.e. you're not running a reverse proxy / webserver config that substitutes the proxy client in the log files). And that you're running fail2ban (or more specifically iptables) on the Linux host, not inside the docker container.

The first thing to check is whether there are any rules defined earlier in the iptables chain which will ACCEPT before the logic gets to the fail2ban DROP.

1
  • Thanks for the hint! There is no proxy whatsoever in use, but actually the server is behind a failover gateway which IP address is added to the network interface. Client IPs are coming in unalterd, but I'll add this information to my question.
    – digijay
    Commented Mar 22 at 10:12
2

Be sure your IP-chains are set up correctly?
Can you check your IP-chain on having an ACCEPT rule before the DROP rules, so there is no drop?

I found this issue at https://github.com/fail2ban/fail2ban/issues/2545

  • "Fail2ban says already banned an IP but the IP can still visit Webserver"
4
  • I've tested iptables with iptables -L | grep -a "180.178.50.130", so I guess that ACCEPT rules show up there? Thanks for the link, I will have a look at it and add the fail2ban version to my question.
    – digijay
    Commented Mar 22 at 10:13
  • That link is really helpful, actually ufw is installed on the server and accepting all requests on http, https before the DROP rules kick in. Thank you very much – and btw Welcome to serverfault!
    – digijay
    Commented Mar 22 at 10:39
  • 1
    @digijay, grep will only show rules that exactly match 180.178.50.130. If you've got any sort of wildcarding, you won't see the relevant rules.
    – Mark
    Commented Mar 23 at 1:15
  • Thanks for the hint @Mark
    – digijay
    Commented Mar 25 at 15:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .