ホーム » 技術 » fail2banをCentOS8にインストールする

fail2banをCentOS8にインストールする

サーバにグローバルIPアドレスを付けるとportscanが激しいので、対策が欠かせない。fail2banは手軽な対策手段なのでオススメなのだが、その原理はscanを検知するとiptablesやfirewall-cmdを使ってフィルタをかけるというものだ。CentOS8になってiptablesからnftablesに移行したのだが、fail2banがきちんと動作するのかが心配になる。これを確かめてみよう。

935

インストール手順

CentOS8では、まだfail2banは標準ではない。ソースからコンパイルするのもよいが、いろいろ面倒なのでパッケージですませよう。 まず最初にEPELを使えるようにする。

dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm

次にfail2banを入れる。

dnf -y install fail2ban python3-inotify

sshの解析だけならinotifyは不要だが、テキストのログ解析をするつもりなら入れておいた方がよいので、ついでに指定しておく。

次にsshdチェックを有効にするために、/etc/fail2ban/jail.localを書く。

[DEFAULT]
banaction = firewallcmd-ipset
banaction_allports = firewallcmd-allports

[sshd]
enabled = true

最後に起動する。

systemctl enable fail2ban
systemctl start fail2ban

動作チェック

CentOS8において、iptablesは廃止されたわけではない。コマンドは残っていて、フィルタを作ったり状態を確認することはできる。iptablesはwrapperになっていて、フィルタリングルールはnftablesのルールセットに変換されるようになっている。iptablesがwrapperか否かは、次のようにすれば確認できる。

[root@c8 ~]# iptables --version
iptables v1.8.2 (nf_tables)

さて上述のようにインストールしたfail2banにsshでアタックするとどうなるだろうか。iptablesのルールを見てみよう。

[root@c8 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
f2b-sshd   tcp  --  0.0.0.0/0            0.0.0.0/0            ctstate NEW multiport dports 22

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  --  116.228.88.115       0.0.0.0/0            reject-with icmp-port-unreachable
REJECT     all  --  164.132.205.21       0.0.0.0/0            reject-with icmp-port-unreachable
REJECT     all  --  177.68.148.10        0.0.0.0/0            reject-with icmp-port-unreachable
RETURN     all  --  0.0.0.0/0            0.0.0.0/0

nftablesのルールセットはこんな感じ。

table ip filter {
        chain INPUT {
                type filter hook input priority 0; policy accept;
                meta l4proto tcp ct state new tcp dport 22 counter packets 12 bytes 720 jump f2b-sshd
        }

        chain FORWARD {
                type filter hook forward priority 0; policy accept;
        }

        chain OUTPUT {
                type filter hook output priority 0; policy accept;
        }

        chain f2b-sshd {
                ip saddr 116.228.88.115 counter packets 0 bytes 0 reject
                ip saddr 164.132.205.21 counter packets 1 bytes 60 reject
                ip saddr 177.68.148.10 counter packets 0 bytes 0 reject
                counter packets 10 bytes 600 return
        }
}

iptablesのルールを、そのまま変換したような感じになっているのが分かる。というわけで互換性を保ちつつ、きちんと動作している。

fail2banのnftablesネイティブルール

/etc/fail2ban/action.dを見てみると、nftablesで始まるネイティブなルールらしきものがある。これをbancactionに指定してみると、なぜかエラーになって動かない。

[sshd]
enabled = yes
banaction = nftables-multiport
banaction_allports = nftables-allports

/var/log/fail2ban.logを確認してみると、こんなエラーになっている(一部抜粋)。

#39-Lev. 7fd6603dc258 -- exec: nft add set inet filter f2b-sshd \{ type ipv4_addr\; \}
ERROR   7fd6603dc258 -- stderr: 'Error: Could not process rule: No such file or directory'
ERROR   7fd6603dc258 -- stderr: 'add set inet filter f2b-sshd { type ipv4_addr; }'
ERROR   7fd6603dc258 -- stderr: '             ^^^^^^'
ERROR   7fd6603dc258 -- stderr: 'Error: Could not process rule: No such file or directory'
ERROR   7fd6603dc258 -- stderr: 'insert rule inet filter input tcp dport { ssh } ip saddr @f2b-sshd reject'
ERROR   7fd6603dc258 -- stderr: '                 ^^^^^^'
ERROR   7fd6603dc258 -- returned 1

ごちゃごちゃして分かりづらいが、inet filterというルールが見つからないので追加に失敗した、と主張しているようだ。nftablesについては完全に理解していないのだが、inetというのは標準で実装されているはずのアドレスファミリだ。だがCentOS8のnftablesではルールセットに定義がない。

ここで2つの選択肢がある。

  1. inet filterを追加して、fail2banが動くようにする
  2. fail2banの方を変更して、既存のルールに追加できるようにする

2の方法については、このページに方法が示されている。

CentOS8の実装では、ipというアドレスファミリは存在しているのでそれにルールを書くようにし、チェイン名を大文字のINPUTに変えればよいようだ。

# オススメしない例 - iptablesが動かなくなる
[sshd]
enabled = true
chain=INPUT
banaction = nftables-multiport[nftables_family=ip]
banaction_allports = nftables-allports[nftables_family=ip]

確かにこの設定ならfail2banは動作する。だが今度はiptablesが文句を言うようになる。

[root@c8 ~]# iptables -nL
iptables v1.8.2 (nf_tables): table `filter' is incompatible, use 'nft' tool.

fail2banが入れるnftablesのルールには後方互換性がなく、iptablesが使えなくなってしまうのだ。これは困る。

そこで1の手法である、fail2banのルールをinet filterの方に入れる手順を試してみる。

nftablesの有効化とinet filterの投入

そもそも、CentOS8にはなぜinet filterのルールセットがないのだろうか。理由はサービスとしてのnftablesはdisabledになっていて、初期化が行われていないから、である。ではCentOS8の初期状態のnftablesのルールセットはどうやって初期化されているのかというと、実はfirewalldが行っている。このため、/etc/nftables/etc/sysconfig/nftables.confも読み込まれない。このままではまずいので、まず最初にnftablesを有効化する。

[root@c8 ~]# systemctl enable nftables
Created symlink /etc/systemd/system/multi-user.target.wants/nftables.service → /usr/lib/systemd/system/nftables.service.

次に/etc/sysconfig/nftables.confを編集する。inet filterを有効化するのが目的なので、ファイル中のコメントアウトされた1行を外すだけでよい。

# include "/etc/nftables/inet-filter.nft"
  ↓
include "/etc/nftables/inet-filter.nft"

ちなみに該当ファイルの内容はこんな感じ。

#!/usr/sbin/nft -f

table inet filter {
        chain input             { type filter hook input priority 0; }
        chain forward           { type filter hook forward priority 0; }
        chain output            { type filter hook output priority 0; }
}

こうしておいてリブート、もしくは次のようにしてルールを読み込む。

nft -f /etc/nftables/inet-filter.nft

これで準備完了だ。これで、エラーになっていたシンプルなルールでfail2banが動作するようになる。再掲載しよう。

[sshd]
enabled = yes
banaction = nftables-multiport
banaction_allports = nftables-allports

今度はエラーにならずに動作するはずだ。nftablesのルールセットの方を確認してみると、このようになる。

table inet filter {
        set f2b-sshd {
                type ipv4_addr
                elements = { 116.228.88.115, 164.132.205.21,
                             177.68.148.10 }
        }

        chain input {
                type filter hook input priority 0; policy accept;
                tcp dport { ssh } ip saddr @f2b-sshd reject
        }

        chain forward {
                type filter hook forward priority 0; policy accept;
        }

        chain output {
                type filter hook output priority 0; policy accept;
        }
}

nftablesネイティブの方が、シンプルでよさそうに見える。

この方法でfail2banを運用すると、iptablesは完全にバイパスすることになる(ルールも入らない)が、別のルールを適用して運用することは全く問題ないので、互換性問題も生じない。

参考リンク