linuxserver / docker-fail2ban

GNU General Public License v3.0
42 stars 7 forks source link

Bans not working #4

Closed mhbates closed 10 months ago

mhbates commented 1 year ago

I'm running some tests and it looks like bans do not actually go into effect. Fail2ban will report the ban, but the IP is still able to access normally.

j0nnymoe commented 1 year ago

You've ignored the issue template we ask you to create.

mhbates commented 1 year ago

Expected Behavior

When an IP is reported as banned by Fail2ban, it should actually be banned and not able to access the server anymore.

Current Behavior

Fail2ban will report the IP ban, but the IP address can continue to access the server as usual.

Steps to Reproduce

  1. For example: Enable the nextcloud-auth jail
  2. Spam Nextcloud login with bogus credentials
  3. Fail2ban reports the IP ban
  4. Nextcloud site continues to load normally and allow login attempts

Environment

OS: Ubuntu 20.04 CPU architecture: x86_64 How docker service was installed: Docker repo

Command used to create docker container (run/create/compose/screenshot)

It's identical to the sample provided. The only differences are timezone, volume mounts, etc.

Docker logs

I'm not seeing anything relevant in either the Docker log or Fail2ban log. The IP is simply reported as banned.

mhbates commented 1 year ago

Also, Nextcloud is running in a container, but it doesn't seem like the ban works regardless of what the chain is set to. I tried all three options and the ban doesn't take with any of them.

nemchik commented 1 year ago

Post you're jail.local

mhbates commented 1 year ago

Please see below. So far I've only tested with Nextcloud, and I've used all three chains, FORWARD is just the latest one I've tested. I restarted the container whenever the config was changed, and of course I tested the IP ban within the 1m ban time :) That was just to be able to test more quickly.

[DEFAULT]

bantime = 1m findtime = 10m maxretry = 1

action = %(action_mwl)s

[nginx-badbots] enabled = true chain = FORWARD port = http,https

logpath = %(nginx_access_log)s

logpath = %(remote_logs_path)s/nginx/fallback_access.log %(remote_logs_path)s/nginx/proxy-host-*_access.log filter = apache-badbots maxretry = 2

[nginx-botsearch] enabled = true chain = FORWARD port = http,https

logpath = %(nginx_error_log)s

logpath = %(remote_logs_path)s/nginx/fallback_error.log %(remote_logs_path)s/nginx/proxy-host-*_error.log

[nginx-http-auth] enabled = true chain = FORWARD port = http,https

logpath = %(nginx_error_log)s

logpath = %(remote_logs_path)s/nginx/fallback_error.log %(remote_logs_path)s/nginx/proxy-host-*_error.log

[nextcloud-auth] enabled = true chain = FORWARD port = http,https logpath = %(remote_logs_path)s/nextcloud/nextcloud.log

[overseerr-auth] enabled = true chain = FORWARD port = 5055 logpath = %(remote_logs_path)s/overseerr/overseerr.log

nemchik commented 1 year ago

For apps running in docker containers, you should use chain = DOCKER-USER

So you should have something like this:

[nextcloud-auth]
enabled = true
chain = DOCKER-USER
port = http,https
logpath = %(remote_logs_path)s/nextcloud/nextcloud.log

This should work as long as you have nextcloud configured to log to the file, and you're running nextcloud on the http (80) and/or https (443) ports inside the container (the nginx configs in our container default to 443 currently, this should work without changing).

The exception to the above would be if you're using a reverse proxy (like swag) and/or using cloudflare's proxy, in which case you would need some additional configuration.

mhbates commented 1 year ago

Thanks. I did try DOCKER-USER as well and that didn't work. I have Nextcloud running behind NGINX Proxy Manager, so it sounds like additional configuration would be needed. NPM is also running as a docker container and uses ports 80 and 443.

I also have Nextcloud behind a Cloudflare proxy. I was hoping this would work just at the NPM level and not the Cloudflare level, in case I move away from Cloudflare at some point.

Do you have or can you point me to any guidance for this kind of setup, particularly NPM? I figured that since it's using the http/https ports, that would still work as expected.

nemchik commented 1 year ago

Thanks. I did try DOCKER-USER as well and that didn't work. I have Nextcloud running behind NGINX Proxy Manager, so it sounds like additional configuration would be needed. NPM is also running as a docker container and uses ports 80 and 443.

I also have Nextcloud behind a Cloudflare proxy. I was hoping this would work just at the NPM level and not the Cloudflare level, in case I move away from Cloudflare at some point.

Do you have or can you point me to any guidance for this kind of setup, particularly NPM? I figured that since it's using the http/https ports, that would still work as expected.

The main thing is nginx needs to be configured to send requests to nextcloud as if it were coming from the IP of the user making the request, NOT from the proxy container itself.

In swag, we include these lines in our proxy.conf

proxy_set_header    X-Forwarded-For  $proxy_add_x_forwarded_for;
proxy_set_header    X-Real-IP        $remote_addr;

(among other things we include out of the box).

mhbates commented 1 year ago

Thanks. I do have NPM configured that way, actual endpoint IPs are passed through.

I'm thinking it's an issue with docker and iptables. I just figured that since this image referred to docker containers, that it would support this kind of setup, but it sounds like it's mainly for restricting access to that container in question, as in Host -> Docker -> Nextcloud, and not Host -> Docker -> NPM -> Nextcloud. I'll have to dig into it more.

nemchik commented 1 year ago

I've tested Host -> Docker -> Swag -> Vaultwarden and that seemed to work as expected. I only did that once for testing, my usual setup is Cloudflare -> Host -> Docker -> Swag -> Vaultwarden and I use the cloudflare action to ban at that level (and also iptables).

github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

ggirou commented 1 year ago

I have same issue, but I have few errors in logs:

 2022-11-24 08:05:13,476 7F8DC29B20 ERROR 7f8e7b1c30 -- stderr: "iptables v1.8.7 (legacy): can't initialize iptables table `filter': Table does not exist (do you need to insmod?)"
 2022-11-24 08:05:13,477 7F8DC29B20 ERROR 7f8e7b1c30 -- stderr: 'Perhaps iptables or your kernel needs to be upgraded.'

Seems to be related to the new nftables available as a modern replacement for the kernel's iptables subsystem on Linux.

ggirou commented 1 year ago

I found a workaround, I hope it will help.

I recreated a new action iptables-nft.local from iptables.conf, replacing iptables commands to iptables-nft.
I also had to replace blocktype = REJECT --reject-with icmp6-port-unreachable to blocktype = DROP.

Then in my jail.local :

action = iptables-nft[type=allports, chain=DOCKER-USER]

Full source of iptables-nft.local bellow:

## Version 2022/08/06iptables-nft
# Fail2Ban configuration file
#
# Authors: Sergey G. Brester (sebres), Cyril Jaquier, Daniel Black, 
#          Yaroslav O. Halchenko, Alexander Koeppe et al.
#

[Definition]

# Option:  type
# Notes.:  type of the action.
# Values:  [ oneport | multiport | allports ]  Default: oneport
#
type = oneport

# Option:  actionflush
# Notes.:  command executed once to flush IPS, by shutdown (resp. by stop of the jail or this action)
# Values:  CMD
#
actionflush = <iptables-nft> -F f2b-<name>

# Option:  actionstart
# 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 = { <iptables-nft> -C f2b-<name> -j <returntype> >/dev/null 2>&1; } || { <iptables-nft> -N f2b-<name> || true; <iptables-nft> -A f2b-<name> -j <returntype>; }
              <_ipt_add_rules>

# Option:  actionstop
# Notes.:  command executed at the stop of jail (or at the end of Fail2Ban)
# Values:  CMD
#
actionstop = <_ipt_del_rules>
             <actionflush>
             <iptables-nft> -X f2b-<name>

# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
#
actioncheck = <_ipt_check_rules>

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionban = <iptables-nft> -I f2b-<name> 1 -s <ip> -j <blocktype>

# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionunban = <iptables-nft> -D f2b-<name> -s <ip> -j <blocktype>

# Option:  pre-rule
# Notes.:  prefix parameter(s) inserted to the begin of rule. No default (empty)
#
pre-rule =

rule-jump = -j <_ipt_rule_target>

# Several capabilities used internaly:

_ipt_for_proto-iter = for proto in $(echo '<protocol>' | sed 's/,/ /g'); do
_ipt_for_proto-done = done

_ipt_add_rules = <_ipt_for_proto-iter>
              { %(_ipt_check_rule)s >/dev/null 2>&1; } || { <iptables-nft> -I <chain> %(_ipt_chain_rule)s; }
              <_ipt_for_proto-done>

_ipt_del_rules = <_ipt_for_proto-iter>
              <iptables-nft> -D <chain> %(_ipt_chain_rule)s
              <_ipt_for_proto-done>

_ipt_check_rules = <_ipt_for_proto-iter>
              %(_ipt_check_rule)s
              <_ipt_for_proto-done>

_ipt_chain_rule = <pre-rule><ipt_<type>/_chain_rule>
_ipt_check_rule = <iptables-nft> -C <chain> %(_ipt_chain_rule)s
_ipt_rule_target = f2b-<name>

[ipt_oneport]

_chain_rule = -p $proto --dport <port> <rule-jump>

[ipt_multiport]

_chain_rule = -p $proto -m multiport --dports <port> <rule-jump>

[ipt_allports]

_chain_rule = -p $proto <rule-jump>

[Init]

# Option:  chain
# Notes    specifies the iptables chain to which the Fail2Ban rules should be
#          added
# Values:  STRING  Default: INPUT
chain = INPUT

# Default name of the chain
#
name = default

# Option:  port
# Notes.:  specifies port to monitor
# Values:  [ NUM | STRING ]  Default:
#
port = ssh

# Option:  protocol
# Notes.:  internally used by config reader for interpolations.
# Values:  [ tcp | udp | icmp | all ] Default: tcp
#
protocol = tcp

# Option:  blocktype
# Note:    This is what the action does with rules. This can be any jump target
#          as per the iptables man page (section 8). Common values are DROP
#          REJECT, REJECT --reject-with icmp-port-unreachable
# Values:  STRING
blocktype = DROP

# Option:  returntype
# Note:    This is the default rule on "actionstart". This should be RETURN
#          in all (blocking) actions, except REJECT in allowing actions.
# Values:  STRING
returntype = RETURN

# Option:  lockingopt
# Notes.:  Option was introduced to iptables to prevent multiple instances from
#          running concurrently and causing irratic behavior.  -w was introduced
#          in iptables 1.4.20, so might be absent on older systems
#          See https://github.com/fail2ban/fail2ban/issues/1122
# Values:  STRING
lockingopt = -w

# Option:  iptables
# Notes.:  Actual command to be executed, including common to all calls options
# Values:  STRING
iptables-nft = iptables-nft <lockingopt>

[Init?family=inet6]

# Option:  blocktype (ipv6)
# Note:    This is what the action does with rules. This can be any jump target
#          as per the iptables man page (section 8). Common values are DROP
#          REJECT, REJECT --reject-with icmp6-port-unreachable
# Values:  STRING
blocktype = DROP

# Option:  iptables (ipv6)
# Notes.:  Actual command to be executed, including common to all calls options
# Values:  STRING
iptables-nft = ip6tables-nft <lockingopt>
github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

ghost commented 1 year ago

Have the same issue

ghost commented 1 year ago

I was able to fix this error by enabling the iptable_raw and ip6table_raw kernel modules on the host.

macross5 commented 1 year ago

I found a workaround, I hope it will help.

I recreated a new action iptables-nft.local from iptables.conf, replacing iptables commands to iptables-nft. I also had to replace blocktype = REJECT --reject-with icmp6-port-unreachable to blocktype = DROP.

Then in my jail.local :

action = iptables-nft[type=allports, chain=DOCKER-USER]

Full source of iptables-nft.local bellow:

## Version 2022/08/06iptables-nft
# Fail2Ban configuration file
#
# Authors: Sergey G. Brester (sebres), Cyril Jaquier, Daniel Black, 
#          Yaroslav O. Halchenko, Alexander Koeppe et al.
#

[Definition]

# Option:  type
# Notes.:  type of the action.
# Values:  [ oneport | multiport | allports ]  Default: oneport
#
type = oneport

# Option:  actionflush
# Notes.:  command executed once to flush IPS, by shutdown (resp. by stop of the jail or this action)
# Values:  CMD
#
actionflush = <iptables-nft> -F f2b-<name>

# Option:  actionstart
# 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 = { <iptables-nft> -C f2b-<name> -j <returntype> >/dev/null 2>&1; } || { <iptables-nft> -N f2b-<name> || true; <iptables-nft> -A f2b-<name> -j <returntype>; }
              <_ipt_add_rules>

# Option:  actionstop
# Notes.:  command executed at the stop of jail (or at the end of Fail2Ban)
# Values:  CMD
#
actionstop = <_ipt_del_rules>
             <actionflush>
             <iptables-nft> -X f2b-<name>

# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
#
actioncheck = <_ipt_check_rules>

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionban = <iptables-nft> -I f2b-<name> 1 -s <ip> -j <blocktype>

# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionunban = <iptables-nft> -D f2b-<name> -s <ip> -j <blocktype>

# Option:  pre-rule
# Notes.:  prefix parameter(s) inserted to the begin of rule. No default (empty)
#
pre-rule =

rule-jump = -j <_ipt_rule_target>

# Several capabilities used internaly:

_ipt_for_proto-iter = for proto in $(echo '<protocol>' | sed 's/,/ /g'); do
_ipt_for_proto-done = done

_ipt_add_rules = <_ipt_for_proto-iter>
              { %(_ipt_check_rule)s >/dev/null 2>&1; } || { <iptables-nft> -I <chain> %(_ipt_chain_rule)s; }
              <_ipt_for_proto-done>

_ipt_del_rules = <_ipt_for_proto-iter>
              <iptables-nft> -D <chain> %(_ipt_chain_rule)s
              <_ipt_for_proto-done>

_ipt_check_rules = <_ipt_for_proto-iter>
              %(_ipt_check_rule)s
              <_ipt_for_proto-done>

_ipt_chain_rule = <pre-rule><ipt_<type>/_chain_rule>
_ipt_check_rule = <iptables-nft> -C <chain> %(_ipt_chain_rule)s
_ipt_rule_target = f2b-<name>

[ipt_oneport]

_chain_rule = -p $proto --dport <port> <rule-jump>

[ipt_multiport]

_chain_rule = -p $proto -m multiport --dports <port> <rule-jump>

[ipt_allports]

_chain_rule = -p $proto <rule-jump>

[Init]

# Option:  chain
# Notes    specifies the iptables chain to which the Fail2Ban rules should be
#          added
# Values:  STRING  Default: INPUT
chain = INPUT

# Default name of the chain
#
name = default

# Option:  port
# Notes.:  specifies port to monitor
# Values:  [ NUM | STRING ]  Default:
#
port = ssh

# Option:  protocol
# Notes.:  internally used by config reader for interpolations.
# Values:  [ tcp | udp | icmp | all ] Default: tcp
#
protocol = tcp

# Option:  blocktype
# Note:    This is what the action does with rules. This can be any jump target
#          as per the iptables man page (section 8). Common values are DROP
#          REJECT, REJECT --reject-with icmp-port-unreachable
# Values:  STRING
blocktype = DROP

# Option:  returntype
# Note:    This is the default rule on "actionstart". This should be RETURN
#          in all (blocking) actions, except REJECT in allowing actions.
# Values:  STRING
returntype = RETURN

# Option:  lockingopt
# Notes.:  Option was introduced to iptables to prevent multiple instances from
#          running concurrently and causing irratic behavior.  -w was introduced
#          in iptables 1.4.20, so might be absent on older systems
#          See https://github.com/fail2ban/fail2ban/issues/1122
# Values:  STRING
lockingopt = -w

# Option:  iptables
# Notes.:  Actual command to be executed, including common to all calls options
# Values:  STRING
iptables-nft = iptables-nft <lockingopt>

[Init?family=inet6]

# Option:  blocktype (ipv6)
# Note:    This is what the action does with rules. This can be any jump target
#          as per the iptables man page (section 8). Common values are DROP
#          REJECT, REJECT --reject-with icmp6-port-unreachable
# Values:  STRING
blocktype = DROP

# Option:  iptables (ipv6)
# Notes.:  Actual command to be executed, including common to all calls options
# Values:  STRING
iptables-nft = ip6tables-nft <lockingopt>

Thank you for your work around. Now I have a other problem:

iptables v1.8.8 (nf_tables): host/network >>>ipv6here<<< not found

Seems like I can't set a full ipv6 as source in the ban command. How do you handle it?

Thanks!

nemchik commented 1 year ago

I haven't fully into the comment from @ggirou but a quick comment regarding block type:

https://github.com/sebres/PoC/blob/master/FW.IDS-DROP-vs-REJECT/README.md from the f2b dev explains whether you should use drop or reject.

Tldr; REJECT if you're using oneport or multiport DROP if you're using allports

macross5 commented 1 year ago

I haven't fully into the comment from @ggirou but a quick comment regarding block type:

https://github.com/sebres/PoC/blob/master/FW.IDS-DROP-vs-REJECT/README.md from the f2b dev explains whether you should use drop or reject.

Tldr; REJECT if you're using oneport or multiport DROP if you're using allports

It's set to allports. Here is the exec: iptables-nft -w -I f2b-vaultwarden-auth 1 -s >>>ipv6here<<< -j DROP from the error log.

I added in the Jail.local action = iptables-nft[type=allports, chain=DOCKER-USER] like it is written in the command from @ggirou.

macross5 commented 1 year ago

Okay, i fixed it for me. First i route all trafic to ip6tables with iptables-nft = ip6tables-nft <lockingopt>. Then its important to do INPUT in the jail.local action = ip6tables-nft[type=allports, chain=INPUT]

Now i get the blocked ipv6 in ip6tables and the trafic will be blocked before it goes into my caddy-network.

github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

hydazz commented 1 year ago

@macross5

can you share your working action and jail config :)

github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. This might be due to missing feedback from OP. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] commented 9 months ago

This issue is locked due to inactivity