使用 fail2ban 和 FirewallD 黑名单保护你的系统
防火墙 fail2ban FirewallD
![](/data/attachment/album/202007/15/124648wugu6bzpw7q5zg72.png)


如果你运行的服务器有面向公众的 SSH 访问，你可能遇到过恶意登录尝试。本文介绍了如何使用两个实用程序来防止入侵者进入我们的系统。


为了防止反复的 ssh 登录尝试，我们来看看 fail2ban。而且，如果你不经常旅行，基本上停留在一两个国家，你可以将 FirewallD 配置为只允许[从你选择的国家访问](https://www.linode.com/community/questions/11143/top-tip-firewalld-and-ipset-country-blacklist)。


首先，让我们为不熟悉这些应用程序的人员介绍一些术语，以完成这项工作：


**fail2ban**：一个守护进程，用于禁止发生多次认证错误的主机。fail2ban 将监控 SystemD 日志，以查找对任何已启用的“<ruby> 监狱 <rt>  jail </rt></ruby>”的失败的验证尝试。在达到指定失败次数后，它将添加一个防火墙规则，在配置的时间内阻止该特定 IP 地址。


**FirewallD**：一个带有 D-Bus 接口的防火墙守护进程，提供动态防火墙。除非你另行决定使用传统的 iptables，否则你已经在所有支持的 Fedora 和 CentOS 上安装了 FirewallD。


### 假定前提


* 主机系统有一个互联网连接，并且要么是直接暴露在互联网上，要么是通过 DMZ（这两个都是非常糟糕的想法，除非你知道你在做什么），要么是有一个端口从路由器转发过来。
* 虽然大部分的内容可能适用于其他系统，但本文假设当前系统是 Fedora（31 及以上）或 RHEL/CentOS 8 版本。在 CentOS 上，你必须用 `sudo dnf install epel-release` 启用 Fedora EPEL 仓库。


### 安装与配置


#### Fail2Ban


很有可能已经有某个 Firewalld 区已经允许 SSH 访问，但 sshd 服务本身默认没有启用。要手动启动它，并且不在启动时永久启用它：



```
$ sudo systemctl start sshd

```

或者在系统启动时启用，并同时启动它：



```
$ sudo systemctl enable --now sshd

```

下一步就是安装、配置、启用 fail2ban。和往常一样，安装可以通过命令行完成：



```
$ sudo dnf install fail2ban

```

安装完毕后，下一步就是配置“监狱”（你要以设置的任何阈值监视并禁止的服务）。默认情况下，IP 会被禁止 1 小时（这其实不够长）。最好的做法是使用 `*.local` 文件覆盖系统默认值，而不是直接修改 `*.config` 文件。如果我们查看我的 `jail.local`，我们可以看到：



```
# cat /etc/fail2ban/jail.local
[DEFAULT]

# "bantime" is the number of seconds that a host is banned.
bantime  = 1d

# A host is banned if it has generated "maxretry" during the last "findtime"
findtime  = 1h

# "maxretry" is the number of failures before a host get banned.
maxretry = 5

```

换成通俗的语言讲，就是在过去一小时内尝试 5 次后，该 IP 将被封禁 1 天。对于多次被封的 IP，也可以选择增加封禁时间，但这是另一篇文章的主题。


下一步是配置“监狱”。在本教程中显示的是 `sshd`，但其他服务的步骤大致相同。在 `/etc/fail2ban/jail.d` 中创建一个配置文件。这是我的文件：



```
# cat /etc/fail2ban/jail.d/sshd.local
[sshd]
enabled = true

```

就这么简单! 很多配置已经在为 Fedora 构建的软件包中处理了（提示：我是当前的维护者）。接下来启用并启动 fail2ban 服务：



```
$ sudo systemctl enable --now fail2ban

```

希望没有立即出错，如果没有，请使用下面的命令检查 fail2ban 的状态：



```
$ sudo systemctl status fail2ban

```

如果它没有错误地启动，应该是这样的：



```
$ systemctl status fail2ban
● fail2ban.service - Fail2Ban Service
Loaded: loaded (/usr/lib/systemd/system/fail2ban.service; disabled; vendor preset: disabled)
Active: active (running) since Tue 2020-06-16 07:57:40 CDT; 5s ago
Docs: man:fail2ban(1)
Process: 11230 ExecStartPre=/bin/mkdir -p /run/fail2ban (code=exited, status=0/SUCCESS)
Main PID: 11235 (f2b/server)
Tasks: 5 (limit: 4630)
Memory: 12.7M
CPU: 109ms
CGroup: /system.slice/fail2ban.service
└─11235 /usr/bin/python3 -s /usr/bin/fail2ban-server -xf start
Jun 16 07:57:40 localhost.localdomain systemd[1]: Starting Fail2Ban Service…
Jun 16 07:57:40 localhost.localdomain systemd[1]: Started Fail2Ban Service.
Jun 16 07:57:41 localhost.localdomain fail2ban-server[11235]: Server ready

```

如果是刚刚启动的，fail2ban 不太可能显示任何有意思的信息，但要检查 fail2ban 的状态，并确保“监狱”被启用，请输入：



```
$ sudo fail2ban-client status
Status
|- Number of jail:      1
`- Jail list:   sshd

```

sshd “监狱”的上级状态也会显示出来。如果启用了多个“监狱”，它们会在这里显示出来。


要查看一个“监狱”的详细状态，只需在前面的命令中添加“监狱”名称。下面是我的系统的输出，它已经运行了一段时间。我已经从输出中删除了被禁止的 IP：



```
$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 8
|  |- Total failed:     4399
|  `- Journal matches:  _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
   |- Currently banned: 101
   |- Total banned:     684
   `- Banned IP list:   ...

```

监控 fail2ban 日志文件是否有入侵尝试，可以通过“尾随”日志来实现：



```
$ sudo tail -f /var/log/fail2ban.log

```

`tail` 是一个很好的命令行工具，默认情况下，它可以显示一个文件的最后 10 行。添加 `-f` 告诉它尾随文件，这是个观察一个仍在被写入的文件的很好方式。


由于输出的内容中有真实的 IP，所以这里不会提供样本，但它的可读性很高。`INFO` 行通常是登录的尝试。如果从一个特定的 IP 地址进行了足够多的尝试，你会看到一个 `NOTICE` 行显示一个 IP 地址被禁止。在达到禁止时间后，你会看到一个 `NOTICE` 解禁行。


注意几个警告行。最常见的情况是，当添加了一个禁止后，fail2ban 发现该 IP 地址已经在其禁止数据库中，这意味着禁止可能无法正常工作。如果是最近安装的 fail2ban 包，它应该被设置为 FirewallD 的富规则。这个包在 fail2ban-0.11.1-6 版本时从 ipset 方式切换到了富规则方式，所以如果你的 fail2ban 安装时间较早，它可能还在尝试使用 ipset 方式，这种方式使用的是传统的 iptables，不是很可靠。


#### FirewallD 配置


##### 被动还是主动？


有两种策略可以分开或一起使用：**被动**地将单个 IP 地址或**主动**地根据来源国将子网永久列入黑名单。


对于被动方式，一旦 fail2ban 运行了一段时间，最好再运行 `sudo fail2ban-client status sshd` 来看看有哪些坏蛋。很可能会有很多被禁止的 IP 地址。选择一个，然后试着对它运行 `whois`。在输出结果中可能会有很多有趣的信息，但是对于这个方法来说，只有来源国是重要的。为了保持简单，让我们过滤掉除了国家以外的所有信息。


在这个例子中，我们将使用一些著名的域名：



```
$ whois google.com | grep -i country
Registrant Country: US
Admin Country: US
Tech Country: US

```


```
$ whois rpmfusion.org | grep -i country
Registrant Country: FR

```


```
$ whois aliexpress.com | grep -i country
Registrant Country: CN

```

使用 `grep -i` 的原因是为了使 `grep` 不区分大小写，而大多数条目都使用的是 “Country”，而有些条目则是全小写的 “country”，所以这种方法无论如何都能匹配。


现在知道了尝试入侵的来源国，问题是，“是否有来自这个国家的人有合法的理由连接到这台计算机？”如果答案是否定的，那么封锁整个国家应该是可以接受的。


从功能上看，主动式方法它与被动式方法没有太大区别，然而，来自有些国家的入侵企图是非常普遍的。如果你的系统既不放在这些国家里，也没有任何源自这些国家的客户，那么为什么不现在就把它们加入黑名单而是等待呢？（LCTT 译注：我的经验是，动辄以国家的范畴而列入黑名单有些过于武断。建议可以将该 IP 所属的 WHOIS 网段放入到黑名单，因为这些网段往往具有相同的使用性质，如都用于用户接入或 IDC 托管，其安全状况也大致相同，因此，如果有来自该网段的某个 IP 的恶意尝试，可以预期该网段内的其它 IP 也可能被利用来做这样的尝试。）


##### 黑名单脚本和配置


那么如何做到这一点呢？用 FirewallD ipset。我开发了下面的脚本来尽可能地自动化这个过程：



```
#!/bin/bash
# Based on the below article
# https://www.linode.com/community/questions/11143/top-tip-firewalld-and-ipset-country-blacklist

# Source the blacklisted countries from the configuration file
. /etc/blacklist-by-country

# Create a temporary working directory
ipdeny_tmp_dir=$(mktemp -d -t blacklist-XXXXXXXXXX)
pushd $ipdeny_tmp_dir

# Download the latest network addresses by country file
curl -LO http://www.ipdeny.com/ipblocks/data/countries/all-zones.tar.gz
tar xf all-zones.tar.gz

# For updates, remove the ipset blacklist and recreate
if firewall-cmd -q --zone=drop --query-source=ipset:blacklist; then
    firewall-cmd -q --permanent --delete-ipset=blacklist
fi

# Create the ipset blacklist which accepts both IP addresses and networks
firewall-cmd -q --permanent --new-ipset=blacklist --type=hash:net \
    --option=family=inet --option=hashsize=4096 --option=maxelem=200000 \
    --set-description="An ipset list of networks or ips to be dropped."

# Add the address ranges by country per ipdeny.com to the blacklist
for country in $countries; do
    firewall-cmd -q --permanent --ipset=blacklist \
        --add-entries-from-file=./$country.zone && \
        echo "Added $country to blacklist ipset."
done

# Block individual IPs if the configuration file exists and is not empty
if [ -s "/etc/blacklist-by-ip" ]; then
    echo "Adding IPs blacklists."
    firewall-cmd -q --permanent --ipset=blacklist \
        --add-entries-from-file=/etc/blacklist-by-ip && \
        echo "Added IPs to blacklist ipset."
fi

# Add the blacklist ipset to the drop zone if not already setup
if firewall-cmd -q --zone=drop --query-source=ipset:blacklist; then
    echo "Blacklist already in firewalld drop zone."
else
    echo "Adding ipset blacklist to firewalld drop zone."
    firewall-cmd --permanent --zone=drop --add-source=ipset:blacklist
fi

firewall-cmd -q --reload

popd
rm -rf $ipdeny_tmp_dir

```

这个应该安装到 `/usr/local/sbin`，不要忘了让它可执行！



```
$ sudo chmod +x /usr/local/sbin/firewalld-blacklist

```

然后创建一个配置文件 `/etc/blacklist-by-country`：



```
# Which countries should be blocked?
# Use the two letter designation separated by a space.
countries=""

```

而另一个配置文件 `/etc/blacklist-by-ip`，每行只有一个 IP，没有任何额外的格式化。


在这个例子中，从 ipdeny 的区文件中随机选择了 10 个国家：



```
# ls | shuf -n 10 | sed "s/\.zone//g" | tr '\n' ' '
nl ee ie pk is sv na om gp bn

```

现在只要在配置文件中加入至少一个国家，就可以运行了！



```
$ sudo firewalld-blacklist
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   142  100   142    0     0   1014      0 --:--:-- --:--:-- --:--:--  1014
100  662k  100  662k    0     0   989k      0 --:--:-- --:--:-- --:--:--  989k
Added nl to blacklist ipset.
Added ee to blacklist ipset.
Added ie to blacklist ipset.
Added pk to blacklist ipset.
Added is to blacklist ipset.
Added sv to blacklist ipset.
Added na to blacklist ipset.
Added om to blacklist ipset.
Added gp to blacklist ipset.
Added bn to blacklist ipset.
Adding ipset blacklist to firewalld drop zone.
success

```

要验证 FirewallD 黑名单是否成功，请检查 `drop` 区和 `blacklist` ipset。



```
$ sudo firewall-cmd --info-zone=drop
drop (active)
  target: DROP
  icmp-block-inversion: no
  interfaces:
  sources: ipset:blacklist
  services:
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

$ sudo firewall-cmd --info-ipset=blacklist | less
blacklist
  type: hash:net
  options: family=inet hashsize=4096 maxelem=200000
  entries:

```

第二条命令将输出所有的子网，这些子网是基于被封杀的国家而添加的，可能会相当长。


### 那么现在我该怎么做？


虽然在开始的时候，监控的频率会比较高，但随着时间的推移，入侵尝试的次数应该会随着黑名单的增加而减少。那么目标应该是维护而不是主动监控。


为此，我创建了一个 SystemD 服务文件和定时器，这样每月都会刷新由 ipdeny 维护的每个国家的子网。事实上，这里讨论的所有内容都可以从我的 [pagure.io](https://pagure.io/firewalld-blacklist) 项目中下载。


是不是很高兴你看完了整篇文章？现在只要把服务文件和定时器下载到 `/etc/systemd/system/`，并启用定时器就行了：



```
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now firewalld-blacklist.timer

```



---


via: <https://fedoramagazine.org/protect-your-system-with-fail2ban-and-firewalld-blacklists/>


作者：[hobbes1069](https://fedoramagazine.org/author/hobbes1069/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
If you run a server with a public-facing SSH access, you might have experienced malicious login attempts. This article shows how to use two utilities to keep the intruder out of our systems.

To protect against repeated ssh login attempts, we’ll look at *fail2ban*. And if you don’t travel much, and perhaps stay in one or two countries, you can configure *firewalld* to only [allow access from the countries you choose](https://www.linode.com/community/questions/11143/top-tip-firewalld-and-ipset-country-blacklist).

First let’s work through a little terminology for those not familiar with the various applications we’ll need to make this work:

**fail2ban:** Daemon to ban hosts that cause multiple authentication errors.

fail2ban will monitor the SystemD journal to look for failed authentication attempts for whichever jails have been enabled. After the number of failed attempts specified it will add a firewall rule to block that specific IP address for an amount of time configured.

**firewalld:** A firewall daemon with D-Bus interface providing a dynamic firewall.

Unless you’ve manually decided to use traditional iptables, you’re already using firewalld on all supported releases of Fedora and CentOS.

## Assumptions

- The host system has an internet connection and is either fully exposed directly, through a DMZ (both REALLY bad ideas unless you know what you’re doing), or has a port being forwarded to it from a router.
- While most of this might apply to other systems, this article assumes a current version of Fedora (31 and up) or RHEL/CentOS 8. On CentOS you must enable the Fedora EPEL repo with
sudo dnf install epel-release

## Install & Configuration

### Fail2Ban

More than likely whichever FirewallD zone is set already allows SSH access but the sshd service itself is not enabled by default. To start it manually and without permanently enabling on boot:

$ sudo systemctl start sshd

Or to start and enable on boot:

$ sudo systemctl enable --now sshd

The next step is to install, configure, and enable fail2ban. As usual the install can be done from the command line:

$ sudo dnf install fail2ban

Once installed the next step is to configure a jail (a service you want to monitor and ban at whatever thresholds you’ve set). By default IPs are banned for 1 hour (which is not near long enough). The best practice is to override the system defaults using *.local files instead of directly modifying the *.config files. If we look at my jail.local we see:

# cat /etc/fail2ban/jail.local [DEFAULT] # "bantime" is the number of seconds that a host is banned. bantime = 1d # A host is banned if it has generated "maxretry" during the last "findtime" findtime = 1h # "maxretry" is the number of failures before a host get banned. maxretry = 5

Turning this into plain language, after 5 attempts within the last hour the IP will be blocked for 1 day. There’s also options for increasing the ban time for IPs that get banned multiple times, but that’s the subject for another article.

The next step is to configure a jail. In this tutorial sshd is shown but the steps are more or less the same for other services. Create a configuration file inside */etc/fail2ban/jail.d*. Here’s mine:

# cat /etc/fail2ban/jail.d/sshd.local [sshd] enabled = true

It’s that simple! A lot of the configuration is already handled within the package built for Fedora (Hint: I’m the current maintainer). Next enable and start the fail2ban service.

$ sudo systemctl enable --now fail2ban

Hopefully there were not any immediate errors, if not, check the status of fail2ban using the following command:

$ sudo systemctl status fail2ban

If it started without errors it should look something like this:

$ systemctl status fail2ban ● fail2ban.service - Fail2Ban Service Loaded: loaded (/usr/lib/systemd/system/fail2ban.service; disabled; vendor preset: disabled) Active: active (running) since Tue 2020-06-16 07:57:40 CDT; 5s ago Docs: man:fail2ban(1) Process: 11230 ExecStartPre=/bin/mkdir -p /run/fail2ban (code=exited, status=0/SUCCESS) Main PID: 11235 (f2b/server) Tasks: 5 (limit: 4630) Memory: 12.7M CPU: 109ms CGroup: /system.slice/fail2ban.service └─11235 /usr/bin/python3 -s /usr/bin/fail2ban-server -xf start Jun 16 07:57:40 localhost.localdomain systemd[1]: Starting Fail2Ban Service… Jun 16 07:57:40 localhost.localdomain systemd[1]: Started Fail2Ban Service. Jun 16 07:57:41 localhost.localdomain fail2ban-server[11235]: Server ready

If recently started, fail2ban is unlikely to show anything interesting going on just yet but to check the status of fail2ban and make sure the jail is enabled enter:

$ sudo fail2ban-client status Status |- Number of jail: 1 `- Jail list: sshd

And the high level status of the sshd jail is shown. If multiple jails were enabled they would show up here.

To check the detailed status a jail, just add the jail to the previous command. Here’s the output from my system which has been running for a while. I have removed the banned IPs from the output:

$ sudo fail2ban-client status sshd Status for the jail: sshd |- Filter | |- Currently failed: 8 | |- Total failed: 4399 | `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd `- Actions |- Currently banned: 101 |- Total banned: 684 `- Banned IP list: ...

Monitoring the fail2ban log file for intrusion attempts can be achieved by “tailing” the log:

$ sudo tail -f /var/log/fail2ban.log

Tail is a nice little command line utility which by default shows the last 10 lines of a file. Adding the “-f” tells it to follow the file which is a great way to watch a file that’s still being written to.

Since the output has real IPs in it, a sample won’t be provided but it’s pretty human readable. The INFO lines will usually be attempts at a login. If enough attempts are made from a specific IP address you will see a NOTICE line showing an IP address was banned. After the ban time has been reached you will see an NOTICE unban line.

Lookout for several WARNING lines. Most often this happens when a ban is added but fail2ban finds the IP address already in its ban database, which means banning may not be working correctly. If recently installed the fail2ban package it should be setup for FirewallD rich rules. The package was only switched from “ipset” to “rich rules” as of *fail2ban-0.11.1-6* so if you have an older install of fail2ban it may still be trying to use the ipset method which utilizes legacy iptables and is not very reliable.

### FirewallD Configuration

#### Reactive or Proactive?

There are two strategies that can be used either separately or together. Reactive or proactive permanent blacklisting of individual IP address or subnets based on country of origin.

For the reactive approach once fail2ban has been running for a while it’s a good idea to take a look at how “bad is bad” by running *sudo fail2ban-client status sshd* again. There most likely will be many banned IP addresses. Just pick one and try running *whois* on it. There can be quite a bit of interesting information in the output but for this method, only the country of origin is of importance. To keep things simple, let’s filter out everything but the country.

For this example a few well known domain names will be used:

$ whois google.com | grep -i country

Registrant Country: US

Admin Country: US

Tech Country: US

$ whois rpmfusion.org | grep -i country

Registrant Country: FR

$ whois aliexpress.com | grep -i country

Registrant Country: CN

The reason for the *grep -i* is to make grep non-case sensitive while most entries use “Country”, some are in all lower case so this method matches regardless.

Now that the country of origin of an intrusion attempt is known the question is, “Does anyone from that country have a legitimate reason to connect to this computer?” If the answer is NO, then it should be acceptable to block the entire country.

Functionally the proactive approach it not very different from the reactive approach, however, there are countries from which intrusion attempts are very common. If the system neither resides in one of those countries, nor has any customers originating from them, then why not add them to the blacklist now rather than waiting?

#### Blacklisting Script and Configuration

So how do you do that? With FirewallD ipsets. I developed the following script to automate the process as much as possible:

#!/bin/bash # Based on the below article # https://www.linode.com/community/questions/11143/top-tip-firewalld-and-ipset-country-blacklist # Source the blacklisted countries from the configuration file . /etc/blacklist-by-country # Create a temporary working directory ipdeny_tmp_dir=$(mktemp -d -t blacklist-XXXXXXXXXX) pushd $ipdeny_tmp_dir # Download the latest network addresses by country file curl -LO http://www.ipdeny.com/ipblocks/data/countries/all-zones.tar.gz tar xf all-zones.tar.gz # For updates, remove the ipset blacklist and recreate if firewall-cmd -q --zone=drop --query-source=ipset:blacklist; then firewall-cmd -q --permanent --delete-ipset=blacklist fi # Create the ipset blacklist which accepts both IP addresses and networks firewall-cmd -q --permanent --new-ipset=blacklist --type=hash:net \ --option=family=inet --option=hashsize=4096 --option=maxelem=200000 \ --set-description="An ipset list of networks or ips to be dropped." # Add the address ranges by country per ipdeny.com to the blacklist for country in $countries; do firewall-cmd -q --permanent --ipset=blacklist \ --add-entries-from-file=./$country.zone && \ echo "Added $country to blacklist ipset." done # Block individual IPs if the configuration file exists and is not empty if [ -s "/etc/blacklist-by-ip" ]; then echo "Adding IPs blacklists." firewall-cmd -q --permanent --ipset=blacklist \ --add-entries-from-file=/etc/blacklist-by-ip && \ echo "Added IPs to blacklist ipset." fi # Add the blacklist ipset to the drop zone if not already setup if firewall-cmd -q --zone=drop --query-source=ipset:blacklist; then echo "Blacklist already in firewalld drop zone." else echo "Adding ipset blacklist to firewalld drop zone." firewall-cmd --permanent --zone=drop --add-source=ipset:blacklist fi firewall-cmd -q --reload popd rm -rf $ipdeny_tmp_dir

This should be installed to */usr/local/sbin* and don’t forget to make it executable!

$ sudo chmod +x /usr/local/sbin/firewalld-blacklist

Then create a configure file: */etc/blacklist-by-country*:

# Which countries should be blocked? # Use the two letter designation separated by a space. countries=""

And another configuration file */etc/blacklist-by-ip*, which is just one IP per line without any additional formatting.

For this example 10 random countries were selected from the ipdeny zones:

# ls | shuf -n 10 | sed "s/\.zone//g" | tr '\n' ' ' nl ee ie pk is sv na om gp bn

Now as long as at least one country has been added to the config file it’s ready to run!

$ sudo firewalld-blacklist % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 142 100 142 0 0 1014 0 --:--:-- --:--:-- --:--:-- 1014 100 662k 100 662k 0 0 989k 0 --:--:-- --:--:-- --:--:-- 989k Added nl to blacklist ipset. Added ee to blacklist ipset. Added ie to blacklist ipset. Added pk to blacklist ipset. Added is to blacklist ipset. Added sv to blacklist ipset. Added na to blacklist ipset. Added om to blacklist ipset. Added gp to blacklist ipset. Added bn to blacklist ipset. Adding ipset blacklist to firewalld drop zone. success

To verify that the firewalld blacklist was successful, check the drop zone and blacklist ipset:

$ sudo firewall-cmd --info-zone=drop drop (active) target: DROP icmp-block-inversion: no interfaces: sources: ipset:blacklist services: ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: $ sudo firewall-cmd --info-ipset=blacklist | less blacklist type: hash:net options: family=inet hashsize=4096 maxelem=200000 entries:

The second command will output all of the subnets that were added based on the countries blocked and can be quite lengthy.

#### So now what do I do?

While it will be a good idea to monitor things more frequently at the beginning, over time the number of intrusion attempts should decline as the blacklist grows. Then the goal should be maintenance rather than active monitoring.

To this end I created a SystemD service file and timer so that on a monthly basis the by country subnets maintained by ipdeny are refreshed. In fact everything discussed here can be downloaded from my pagure.io project:

[https://pagure.io/firewalld-blacklist](https://pagure.io/firewalld-blacklist)

Aren’t you glad you read the whole article? Now just download the service file and timer to */etc/systemd/system/ *and enable the timer:

$ sudo systemctl daemon-reload $ sudo systemctl enable --now firewalld-blacklist.timer

## K. de Jong

“If you run a server with a public-facing SST access”, do you mean SSH? If not, please add the acronym in full or a hyperlink for more info.

## Pieter

Thank you for this great article and the firewalld-blacklist repo!

## Ron Olson

Great article! FYI If you’re doing this from CentOS, you need to first run

sudo dnf install epel-release

to get the packages.

## Stephen Snow

Thanks Ron,

Good catch!

## Leo L. B.

fail2ban doesnt protect against distributed bruteforce attacks coming from several hosts at the same time, which is what the bruteforce attempts you get over SSH are when you run a public facing server.

Maybe you could talk about Port Knocking and how it can stop port scanning and therefore these distributed bruteforce attacks completely?

Good article nonetheless!

## Joao Rodrigues

If you really want to stop worrying about brute force attacks, the only way is to completely disable password authentication and rely on public keys or client certificate authentication.

## Elio Qoshi

Bonus points if you could change ‘Blacklist’ to a less discriminatory term, such as “Blocklist” or ‘Deny List’ 🙂

## Till Maas

Thank you for highlighting this. This is currently tracked/discussed at https://lists.fedoraproject.org/archives/list/magazine@lists.fedoraproject.org/thread/TJUHPD2ANXHYNAKVXYRYNHDLCPPAKNYI/

## Paul W. Frields

Although this article was planned and written some time before publication, and before people were starting to have discussions in IT about the use of these terms, that doesn’t make it any less of an issue. The editors are aware of the concern, and are having a discussion currently about new guidelines for standard usage, including using “allowlist/denylist.” Work is already underway on those guidelines. One thing to note in that discussion — there is plenty of input from many quarters already, but much of the input is not coming from editors. As with other open source communities, the people who do the work get to make the decisions on what to do here, and the editors seem to be largely in agreement about fixing this.

## Randy

BLOCKlists 🙄 c’mon

## Luya Tshimbalanga

Small correction. “Systemd” instead of “SystemD”.

## sieukeo.com

Glad to bе one of many visitants on tһis awing site

:D.

## francesco

Suddenly it looks like fail2ban doesn’t support IPv6 (I’m a Debian user, so I’m not sure about Fedora…)

Here you can find more info:

https://github.com/fail2ban/fail2ban/issues/39

That’s why I uncomment the line:

ListenAddress 0.0.0.0

in the sshd config file (/etc/ssh/sshd_config on my system).

sshd will then listen only on IPv4.

## francesco

I’m sorry, I didn’t notice that the issue was closed a few years ago… so fail2ban supports IPv6 too, now.

## Brooks Kelley

Thank you for posting this article. How timely too!

I had just upgraded from Fedora 29 to 32 ( yes, I know, big leap ).

I have been used to using IPTABLES to exclude countries from accessing my SSH server. I was not looking forward to the learning curve for NFTABLES to do what I used to do for my SSH server with IPTABLES. I finally gave up and just secured my SSH server to not being accessible from the cloud when I saw this article posted.

I have limited now my access to the US and CN. I also set the failure rate to 3 instead of 5. In addition, I extended the attempts time to two hours and the ban to two days.

After installing the script and running it, I VPNed into France and tried to access my SSH server using my FQDN. No response! 😎

Before adding the country blacklist though, I just ran fail2bain for a couple of days. I had somewhere around 345 bans in effect by the time I installed your scripts for firewalld and ipsets.

What I would love to see is the article you promised following up on how if someone shows up again on the BAN list, you can extend their BANTIME even further or even permanently.

I would really love to know how to do that. My server is a private server and I don’t mind making it as hard as possible to gain access via SSH. I have turned off direct root access. Of course, I could go further with keys and may do so. But, I would rather install some sort of two factor authentication over the use of keys.

Thank you again for posting this!

## Marcwa

I cam across this and in the first shot it was not working for me using Fedora 32.

I noticed, that i added the Country-Lists with uppercase characters in /etc/blacklist-by-country.

So i adjusted the Code of firewalld-blacklist a little bit, that it converts the country code to lowercase characters.

To do so, just change on line from:

“–add-entries-from-file=./$country.zone && \”

to

“–add-entries-from-file=./${country,,}.zone && \”

Now it is working perfectly! Thank you very much for this guide.

## Brooks Kelley

Last night, I had to shut down my server. It’s okay. It is just a toy I use to learn on trying out server software. Our home network’s LAN was experiencing a data storm and devices weren’t working. Afterwards, things returned to normal on the network. I went into the cable router and shutdown port forwarding to my server.

Upon examining the fail2ban.log file this morning, I found the fail2ban service restarted around 9 in the morning, which is odd since I was leaving the system alone. Twenty-five minutes later everything shut down in the log file for the remainder of the day. Of course, this left my system vulnerable for the rest of the day to a brute force attack. By the evening, my network was in disarray. I suspect a vulnerability of fail2ban has been found.

I went to their website and was shocked to find that it hasn’t been updated since 2015.

The worse part is that fail2ban shuts down logging on ‘secure’ so I couldn’t see what was going on with my ssh server independently of my fail2ban service after it failed.

This is the last of my fail2ban log file. The abuser is from China. …

2020-07-04 09:25:30,175 fail2ban.actions [767]: NOTICE [sshd] Restore Ban 106.12.88.165

2020-07-04 09:26:30,212 fail2ban.utils [767]: ERROR 7f974829f630 — exec: ports=”ssh”; for p in $(echo $ports | tr “, ” ” “); do firewall-cmd –add-rich-rule=”rule family=’ipv4′ source address=’106.12.88.165′ port port=’$p’ protocol=’tcp’ reject type=’icmp-port-unreachable'”; done

2020-07-04 09:26:30,213 fail2ban.utils [767]: ERROR 7f974829f630 — timed out after 60 seconds.

2020-07-04 09:26:30,413 fail2ban.utils [767]: ERROR ports=”ssh”; for p in $(echo $ports | tr “, ” ” “); do firewall-cmd –add-rich-rule=”rule family=’ipv4′ source address=’106.12.88.165′ port port=’$p’ protocol=’tcp’ reject type=’icmp-port-unreachable'”; done — failed with [Errno 3] No such process

2020-07-04 09:26:30,413 fail2ban.utils [767]: ERROR 7f974829f630 — stderr: ‘ERROR:dbus.proxies:Introspect error on :1.7:/org/fedoraproject/FirewallD1: dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.’

2020-07-04 09:26:30,413 fail2ban.utils [767]: ERROR 7f974829f630 — killed with SIGTERM (return code: -15)

2020-07-04 09:26:30,414 fail2ban.actions [767]: ERROR Failed to execute ban jail ‘sshd’ action ‘firewallcmd-rich-rules’ info ‘ActionInfo({‘ip’: ‘106.12.88.165’, ‘family’: ‘inet4’, ‘fid’: <function Actions.ActionInfo. at 0x7f9748fcfe50>, ‘raw-ticket’: <function Actions.ActionInfo. at 0x7f9748fd0550>})’: Error banning 106.12.88.165

## Tim

If you want to block visitors by country using ipset, you can find the instructions in https://blog.ip2location.com/knowledge-base/how-to-block-ip-addresses-from-a-country-using-ipset/