0

I installed fail2ban 0.10.2-2.1 on Raspbian Buster to protect ssh (and if that works, apache). The default installation only enables de sshd jail, but in my case that does not seem to work. The fail2ban-client reports that the jail is running:

$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed: 0
|  `- File list:    /var/log/auth.log
`- Actions
   |- Currently banned: 0
   |- Total banned: 0
   `- Banned IP list:

However, when I check if iptables rules are created, it shows no chains are created, and nothing is banned:

$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

As far as I understand, I expect a f2b-sshd chain to be in that list. I checked the logfile, and even when I configure fail2ban.conf to outout DEBUG level, I don't see any iptables actions:

2020-02-25 22:36:44,325 fail2ban.server         [28901]: INFO    --------------------------------------------------
2020-02-25 22:36:44,325 fail2ban.server         [28901]: INFO    Starting Fail2ban v0.10.2
2020-02-25 22:36:44,327 fail2ban.server         [28901]: DEBUG   Creating PID file /var/run/fail2ban/fail2ban.pid
2020-02-25 22:36:44,327 fail2ban.server         [28901]: DEBUG   Starting communication
2020-02-25 22:36:44,332 fail2ban.database       [28901]: INFO    Connected to fail2ban persistent database '/var/lib/fail2ban/fail2ban.sqlite3'
2020-02-25 22:36:44,337 fail2ban.jail           [28901]: INFO    Creating new jail 'sshd'
2020-02-25 22:36:44,381 fail2ban.jail           [28901]: INFO    Jail 'sshd' uses pyinotify {}
2020-02-25 22:36:44,382 fail2ban.filter         [28901]: DEBUG   Setting usedns = warn for FilterPyinotify(Jail('sshd'))
2020-02-25 22:36:44,382 fail2ban.filter         [28901]: DEBUG   Created FilterPyinotify(Jail('sshd'))
2020-02-25 22:36:44,393 fail2ban.filterpyinotify[28901]: DEBUG   Created FilterPyinotify
2020-02-25 22:36:44,393 fail2ban.jail           [28901]: INFO    Initiated 'pyinotify' backend
2020-02-25 22:36:44,396 fail2ban.filter         [28901]: INFO      maxLines: 1
2020-02-25 22:36:44,397 fail2ban.server         [28901]: DEBUG     prefregex: '^<F-MLFID>(?:\\[\\])?\\s*(?:<[^.]+\\.[^.]+>\\s+)?(?:\\S+\\s+)?(?:kernel: \\[ *\\d+\\.\\d+\\]\\s+)?(?:@vserver_\\S+\\s+)?(?:(?:(?:\\[\\d+\\])?:\\s+[\\[\\(]?sshd(?:\\(\\S+\\))?[\\]\\)]?:?|[\\[\\(]?sshd(?:\\(\\S+\\))?[\\]\\)]?:?(?:\\[\\d+\\])?:?)\\s+)?(?:\\[ID \\d+ \\S+\\]\\s+)?</F-MLFID>(?:(?:error|fatal): (?:PAM: )?)?<F-CONTENT>.+</F-CONTENT>$'
2020-02-25 22:36:44,413 fail2ban.server         [28901]: DEBUG     failregex: '^[aA]uthentication (?:failure|error|failed) for <F-USER>.*</F-USER> from <HOST>( via \\S+)?\\s*(?: \\[preauth\\])?\\s*$'
...SNIP...
2020-02-25 22:36:44,513 fail2ban.server         [28901]: DEBUG     failregex: '^<F-MLFFORGET><F-NOFAIL>Accepted publickey</F-NOFAIL></F-MLFFORGET> for \\S+ from <HOST>(?:\\s|$)'
2020-02-25 22:36:44,518 fail2ban.server         [28901]: DEBUG     failregex: '^<F-NOFAIL>Connection from</F-NOFAIL> <HOST>'
2020-02-25 22:36:44,524 fail2ban.datetemplate   [28901]: DEBUG     constructed regex (?:^|\b|\W)((?P<Y>(?:202|201)\d)(?P<_sep>[-/.])(?P<m>1[0-2]|0[1-9]|[1-9])(?P=_sep)(?P<d>3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])(?:T|  ?)(?P<H>2[0-3]|[0-1]\d|\d):(?P<M>[0-5]\d|\d):(?P<S>6[0-1]|[0-5]\d|\d)(?:[.,](?P<f>[0-9]{1,6}))?(?:\s*(?P<z>Z|UTC|GMT|[+-][01]\d(?::?\d{2})?))?)(?=\b|\W|$)
2020-02-25 22:36:44,525 fail2ban.datetemplate   [28901]: DEBUG     constructed regex ^(?:\W{0,2})?((?P<Y>(?:202|201)\d)(?P<_sep>[-/.])(?P<m>1[0-2]|0[1-9]|[1-9])(?P=_sep)(?P<d>3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])(?:T|  ?)(?P<H>2[0-3]|[0-1]\d|\d):(?P<M>[0-5]\d|\d):(?P<S>6[0-1]|[0-5]\d|\d)(?:[.,](?P<f>[0-9]{1,6}))?(?:\s*(?P<z>Z|UTC|GMT|[+-][01]\d(?::?\d{2})?))?)(?=\b|\W|$)
2020-02-25 22:36:44,526 fail2ban.datetemplate   [28901]: DEBUG     constructed regex (?:^|\b|\W)(?iu)((?:(?P<a>mon|tue|wed|thu|fri|sat|sun) )?(?P<b>jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec) (?P<d>3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])  ?(?P<H>[0-2]?\d):(?P<M>[0-5]\d|\d):(?P<S>6[0-1]|[0-5]\d|\d)(?:\.(?P<f>[0-9]{1,6}))?(?: (?P<Y>(?:202|201)\d))?)(?=\b|\W|$)
...SNIP...
2020-02-25 22:36:44,544 fail2ban.datetemplate   [28901]: DEBUG     constructed regex ^(?:\W{0,2})?(?iu)((?:(?P<z>Z|UTC|GMT|[+-][01]\d(?::?\d{2})?) )?(?:(?P<a>mon|tue|wed|thu|fri|sat|sun) )?(?P<b>jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec) (?P<d>3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])  ?(?P<H>[0-2]?\d):(?P<M>[0-5]\d|\d):(?P<S>6[0-1]|[0-5]\d|\d)(?:\.(?P<f>[0-9]{1,6}))?(?: (?P<Y>(?:202|201)\d))?)(?=\b|\W|$)
2020-02-25 22:36:44,545 fail2ban.datetemplate   [28901]: DEBUG     constructed regex (@[0-9a-f]{24})(?=\b|\W|$)
2020-02-25 22:36:44,545 fail2ban.datetemplate   [28901]: DEBUG     constructed regex ^(?:\W{0,2})?(@[0-9a-f]{24})(?=\b|\W|$)
2020-02-25 22:36:44,546 fail2ban.server         [28901]: INFO    Jail sshd is not a JournalFilter instance
2020-02-25 22:36:44,549 fail2ban.filter         [28901]: INFO    Added logfile: '/var/log/auth.log' (pos = 111389, hash = 88b5563c0ca8a36a0cc3a0fa6c6110a8a17ca4aa)
2020-02-25 22:36:44,550 fail2ban.filterpyinotify[28901]: DEBUG   New <Watch wd=1 path=/var/log mask=1073745280 proc_fun=None auto_add=False exclude_filter=<function WatchManager.<lambda> at 0x754a8e40> dir=True >
2020-02-25 22:36:44,551 fail2ban.filterpyinotify[28901]: DEBUG   Added monitor for the parent directory /var/log
2020-02-25 22:36:44,551 fail2ban.filterpyinotify[28901]: DEBUG   New <Watch wd=2 path=/var/log/auth.log mask=2 proc_fun=None auto_add=False exclude_filter=<function WatchManager.<lambda> at 0x754a8e40> dir=False >
2020-02-25 22:36:44,552 fail2ban.filterpyinotify[28901]: DEBUG   Added file watcher for /var/log/auth.log
2020-02-25 22:36:44,552 fail2ban.filter         [28901]: DEBUG   Seek to find time 1582666004.5494933 (2020-02-25 22:26:44), file size 111470
2020-02-25 22:36:44,566 fail2ban.filter         [28901]: DEBUG   Position 111389 from 111470, found time 1582666603.0 (2020-02-25 22:36:43) within 1 seeks
2020-02-25 22:36:44,568 fail2ban.filter         [28901]: INFO      encoding: UTF-8
2020-02-25 22:36:44,569 fail2ban.filter         [28901]: INFO      maxRetry: 5
2020-02-25 22:36:44,570 fail2ban.filter         [28901]: INFO      findtime: 1800
2020-02-25 22:36:44,571 fail2ban.actions        [28901]: INFO      banTime: 1800
2020-02-25 22:36:44,572 fail2ban.filter         [28901]: DEBUG   Setting usedns = warn for FilterPyinotify(Jail('sshd'))
2020-02-25 22:36:44,574 fail2ban.filter         [28901]: DEBUG     Add '10.0.0.0/8' to ignore list ('10.0.0.21/8')
2020-02-25 22:36:44,575 fail2ban.filter         [28901]: DEBUG     Add '127.0.0.0/8' to ignore list ('127.0.0.1/8')
2020-02-25 22:36:44,576 fail2ban.filter         [28901]: DEBUG     Add '::1' to ignore list ('::1')
2020-02-25 22:36:44,577 fail2ban.CommandAction  [28901]: DEBUG   Created <class 'fail2ban.server.action.CommandAction'>
2020-02-25 22:36:44,578 fail2ban.CommandAction  [28901]: DEBUG     Set actionstart = '<iptables> -N f2b-sshd\n<iptables> -A f2b-sshd -j RETURN\n<iptables> -I INPUT -p tcp -m multiport --dports ssh -j f2b-sshd'
2020-02-25 22:36:44,579 fail2ban.CommandAction  [28901]: DEBUG     Set actionstop = '<iptables> -D INPUT -p tcp -m multiport --dports ssh -j f2b-sshd\n<iptables> -F f2b-sshd\n<iptables> -X f2b-sshd'
2020-02-25 22:36:44,579 fail2ban.CommandAction  [28901]: DEBUG     Set actionflush = '<iptables> -F f2b-sshd'
2020-02-25 22:36:44,579 fail2ban.CommandAction  [28901]: DEBUG     Set actioncheck = "<iptables> -n -L INPUT | grep -q 'f2b-sshd[ \\t]'"
2020-02-25 22:36:44,580 fail2ban.CommandAction  [28901]: DEBUG     Set actionban = '<iptables> -I f2b-sshd 1 -s <ip> -j <blocktype>'
2020-02-25 22:36:44,580 fail2ban.CommandAction  [28901]: DEBUG     Set actionunban = '<iptables> -D f2b-sshd -s <ip> -j <blocktype>'
2020-02-25 22:36:44,580 fail2ban.CommandAction  [28901]: DEBUG     Set name = 'sshd'
2020-02-25 22:36:44,581 fail2ban.CommandAction  [28901]: DEBUG     Set bantime = '1800'
2020-02-25 22:36:44,581 fail2ban.CommandAction  [28901]: DEBUG     Set port = 'ssh'
2020-02-25 22:36:44,581 fail2ban.CommandAction  [28901]: DEBUG     Set protocol = 'tcp'
2020-02-25 22:36:44,581 fail2ban.CommandAction  [28901]: DEBUG     Set chain = '<known/chain>'
2020-02-25 22:36:44,581 fail2ban.CommandAction  [28901]: DEBUG     Set actname = 'iptables-multiport'
2020-02-25 22:36:44,582 fail2ban.CommandAction  [28901]: DEBUG     Set blocktype = 'REJECT --reject-with icmp-port-unreachable'
2020-02-25 22:36:44,582 fail2ban.CommandAction  [28901]: DEBUG     Set returntype = 'RETURN'
2020-02-25 22:36:44,582 fail2ban.CommandAction  [28901]: DEBUG     Set lockingopt = '-w'
2020-02-25 22:36:44,582 fail2ban.CommandAction  [28901]: DEBUG     Set iptables = 'iptables <lockingopt>'
2020-02-25 22:36:44,583 fail2ban.CommandAction  [28901]: DEBUG     Set blocktype?family=inet6 = 'REJECT --reject-with icmp6-port-unreachable'
2020-02-25 22:36:44,583 fail2ban.CommandAction  [28901]: DEBUG     Set iptables?family=inet6 = 'ip6tables <lockingopt>'
2020-02-25 22:36:44,584 fail2ban.jail           [28901]: DEBUG   Starting jail 'sshd'
2020-02-25 22:36:44,585 fail2ban.filterpyinotify[28901]: DEBUG   [sshd] filter started (pyinotifier)
2020-02-25 22:36:44,587 fail2ban.jail           [28901]: INFO    Jail 'sshd' started

I tried switching from pyinotify to gamin and polling mode to no avail. I tried creating separate configuration files, and adding explicit references to filter.d files, but nothing seems to help.

The regular expression matcher does report that matches are found:

$ fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf

Running tests
=============

Use   failregex filter file : sshd, basedir: /etc/fail2ban
Use         maxlines : 1
Use      datepattern : Default Detectors
Use         log file : /var/log/auth.log
Use         encoding : UTF-8


Results
=======

Failregex: 19 total
|-  #) [# of hits] regular expression
|   6) [1] ^[iI](?:llegal|nvalid) user <F-USER>.*?</F-USER> from <HOST>(?: port \d+)?(?: on \S+(?: port \d+)?)?\s*$
|  20) [18] ^<F-MLFFORGET><F-NOFAIL>Accepted publickey</F-NOFAIL></F-MLFFORGET> for \S+ from <HOST>(?:\s|$)
`-

Ignoreregex: 0 total

Date template hits:
|- [# of hits] date format
|  [1143] {^LN-BEG}(?:DAY )?MON Day %k:Minute:Second(?:\.Microseconds)?(?: ExYear)?
`-

Lines: 1143 lines, 0 ignored, 19 matched, 1124 missed
[processed in 0.81 sec]

Missed line(s): too many to print.  Use --print-all-missed to print all 1124 lines

It seems to me according to the documentation that the default installation of fail2ban should at least create iptables chains, which it does not do. What am I missing here?

Rolf
  • 141
  • 5
  • One check I didn't do is a manual ban, such as described in [this answer](https://serverfault.com/a/957675). I need to test that tonight and update this question with the results. – Rolf Feb 26 '20 at 10:07

1 Answers1

3

It turns out that the answer is twofold. First, there is a change in how fail2ban works. Newer versions of fail2ban will not immediately create chains in the firewall configuration, but only upon first trigger. This explains why a new fail2ban installation does not show chains in iptables -L.

To test the creation of the iptables chains, we can use the fail2ban-client to add a ban (-vvv to add verbosity which may help you debug problems in the command):

$ sudo fail2ban-client -vvv set sshd banip 192.0.2.0

After running this command, iptables shows (should show) the chain for this jail:

$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
f2b-sshd   tcp  --  anywhere             anywhere             multiport dports ssh

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain f2b-sshd (1 references)
target     prot opt source               destination
REJECT     all  --  192.0.2.0            anywhere             reject-with icmp-port-unreachable
RETURN     all  --  anywhere             anywhere

We can unban the ip as follows:

$ sudo fail2ban-client -vvv set sshd unbanip 192.0.2.0

And now the rule in iptables is removed, but the f2b-sshd chain persists:

$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
f2b-sshd   tcp  --  anywhere             anywhere             multiport dports ssh

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain f2b-sshd (1 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere

In short, to test your fail2ban installation you must:

  1. Install fail2ban with just the sshd configuration (which is default)
  2. Use sudo fail2ban-client status sshd to check the status
  3. Use fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf to check the regular expression matching.
  4. Use sudo fail2ban-client -vvv set sshd banip 192.0.2.0 to generate an sshd ban
  5. Use sudo iptables -L to verify that the f2b-sshd chain is created with the ban rule in it.
  6. Use sudo fail2ban-client -vvv set sshd unbanip 192.0.2.0 to remove the ban.

I also noticed that there is an option to revert the "on demand chain creation" behavior, check this github issue for details

I hope this helps.

Rolf
  • 141
  • 5