Fail2banとNftablesでLinuxへのブルートフォース攻撃を遮断する

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

SSH自動スキャンと認証不正アクセスの実態

マネージドではないプレーンなVPSを立ち上げ、ポート22をインターネットに公開してログを監視してみてください。わずか15分足らずで、自動化されたボットによるアクセス試行が始まります。公開サーバーは通常、毎日1,000〜5,000件もの不正な認証試行を受けており、スキャナーはroot、admin、deploy、testといったよくあるアカウントを対象にクレデンシャルダンプを総当たりで試行します。

根本的なボトルネックは、SSHの動作仕様にあります。OpenSSHはパスワードを検証する前に、まずTCP接続を確立し、暗号鍵の交換を完了させ、セッションキーを計算します。このハンドシェイク処理は計算負荷が非常に高い処理です。これが毎分数回〜数十回発生すると、不正なスキャナーによってCPUリソースが浪費され、システムログ(/var/log/auth.logまたはsystemdジャーナル)が埋め尽くされ、脆弱なパスワードを持つアカウントが執拗に探索され続けることになります。

公開鍵認証への移行や非標準ポートの利用も効果的ですが、不要なトラフィックそのものを排除できるわけではありません。ユーザーランドのデーモンに到達する前に、カーネルレベルで悪意あるパケットを破棄する自動境界防御が必要不可欠です。

パケットフィルタリングエンジンのアーキテクチャ比較

ログ監視とパケットフィルターの連携自体は新しい手法ではありません。長年、システム管理者はiptablesやアプリケーション層のラッパーに依存してきました。しかし現在では、nftablesを採用することで根本的に優れたアプローチが可能になっています。

大量の攻撃トラフィック下における、主に使われる3つのパケット遮断戦略の挙動の違いは以下のとおりです。

  • Fail2ban + レガシーiptables: BANされたIPごとに個別の-j DROPルールを追加します。ボットネットによる組織的な攻撃を受け、ブロックリストが5,000件を超えると、Linuxカーネルは受信パケットをすべてのルールに対して順次評価しなければならなくなります。このO(N)の線形評価は、正常な接続に対しても顕著なレイテンシを生じさせます。
  • TCP Wrappers(hosts.deny) / アプリケーション拒否リスト: トラフィックを完全にユーザー空間でブロックします。カーネルは依然として3ウェイTCPハンドシェイクを完了し、デーモンプロセスを起動するため、RAM、ソケットハンドル、コンテキストスイッチが無駄に消費されます。
  • Fail2ban + Nftablesセット: BAN対象のアドレスをカーネルの不可分なセット(set)に直接書き込みます。検索のオーバーヘッドは線形探索のO(N)から、ハッシュテーブルによるO(1)検索へと削減されます。BAN対象が15件であっても50,000件であっても、フィルタリングの処理速度は極めて高速なまま維持されます。

Nftables統合のメリットとデメリット

インフラ全体でnftablesを標準化する前に、運用上のトレードオフを把握しておきましょう。

メリット

  • 予測可能なCPU・メモリオーバーヘッド: 数千件に及ぶブロック対象IPをネイティブなハッシュセット内に保持するため、パケットフィルタリングを軽量に保てます。持続的な20,000件のBANが発生している2 vCPU / 4 GB RAMの一般的なクラウドインスタンスでも、パケット検査中のカーネルCPU使用率はほぼフラットな状態を維持します(iptablesの場合、softirq負荷が15%を超えることがあります)。
  • アトミックなセット操作: アクティブなファイアウォールルールセット全体をフラッシュしたり再構築したりすることなく、Fail2banがメモリ内の要素を動的に追加・削除できます。
  • IPv4とIPv6の統合管理: iptablesとip6tablesのコマンドを個別に実行する代わりに、単一のinetファミリテーブル内でデュアルスタックのフィルタリングを一元管理できます。

デメリット

  • 従来のコマンド体系への慣れ: システムに互換レイヤーが導入されていない限り、使い慣れたiptables -L -nなどのコマンドではnftablesセット内に格納されたアクティブなBAN情報を確認できません。
  • パッケージ要件: 安定したnftablesセットアクションを利用するには、Fail2ban 0.11.x以降が必要です。古いディストリビューション上で稼働するレガシーシステムを運用している場合は、バックポートが必要になります。

推奨環境

本手順は、Linuxカーネル5.4以降を実行する最新のディストリビューション(Debian 11/12、Ubuntu 22.04/24.04、AlmaLinux 9、Rocky Linux 9など)を対象としています。Fail2ban 1.0以上とネイティブなNftablesセットをnftables-multiportアクションで連携させ、認証イベントをsystemdジャーナルから直接読み込みます。

実装ガイド

1. 必要なパッケージのインストール

システムのパッケージマネージャーを使用して、両方のパッケージをインストールします。

# Ubuntu / Debian の場合
sudo apt update
sudo apt install -y fail2ban nftables

# AlmaLinux / Rocky Linux / RHEL 9 の場合
sudo dnf install -y epel-release
sudo dnf install -y fail2ban nftables

nftablesパケットエンジンを有効化して起動します。

sudo systemctl enable --now nftables

2. Fail2banのグローバルデフォルト設定

/etc/fail2ban/jail.confを直接編集しないでください。パッケージのアップデート時に変更内容が上書きされてしまいます。代わりに、/etc/fail2ban/jail.localに専用のオーバーライドファイルを作成してカスタムルールを配置します。

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local

[DEFAULT]セクションを見つけ、以下の設定を適用して信頼できるIP範囲、BANタイマー、およびnftablesアクションを指定します。

[DEFAULT]
# ローカルホストおよび社内VPN/オフィスのサブネットを除外
ignoreip = 127.0.0.1/8 ::1 10.8.0.0/24 192.168.1.50

# 監視時間枠と検知しきい値
findtime = 10m
maxretry = 5
bantime  = 1h

# 指数バックオフ: 執拗なボットに対するペナルティを段階的に増加
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 4w

# トラフィックの破棄処理をカーネルレベルのnftablesセットに直接指示
banaction = nftables-multiport
banaction_allports = nftables-allports

3. SSH用Jailの定義

サービスのjail定義は、個別の設定ファイルに分けることでモジュール性を維持します。/etc/fail2ban/jail.d/sshd.localを作成します。

[sshd]
enabled  = true
port     = ssh
backend  = systemd
maxretry = 3
findtime = 10m
bantime  = 24h

4. フィルタールールの検証とテスト

Fail2banは、/etc/fail2ban/filter.d/内に定義された正規表現パターンに沿ってログストリームを解析します。本番環境でjailを有効化する前に、正規表現がお使いのディストリビューションの実際のログ形式に一致しているか確認してください。

sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf

出力されたサマリーを確認します。ジャーナル内のパスワード認証失敗や無効なユーザーによるリクエストにルールが一致していれば、BAN適用の準備は完了です。

5. Fail2banの起動とカーネル状態の確認

設定を反映し、デーモンを起動します。

sudo systemctl enable --now fail2ban

fail2ban-clientでjailの状態を確認します。

sudo fail2ban-client status sshd

攻撃者がしきい値に達すると、nftablesがパケットの破棄を処理します。膨大なルールリストを作成する代わりに、nftablesはコンパクトな名前付きセット内でBAN対象を管理します。

sudo nft list table inet f2b-table

出力結果から、高速なカーネルセット内にアクティブな要素が格納されていることが確認できます。

table inet f2b-table {
    set addr-set-sshd {
        type ipv4_addr
        elements = { 198.51.100.23, 203.0.113.88 }
    }

    chain f2b-chain-sshd {
        type filter hook input priority filter - 1; policy accept;
        meta l4proto tcp ip saddr @addr-set-sshd tcp dport 22 drop
    }
}

6. 手動BANと緊急解除の管理

エンジニアが自宅から誤ってBANされてしまった場合や、悪質なスキャナーを手動でブロックしたい場合は、設定ファイルを直接編集することなくクライアントコマンドから操作できます。

# 誤って適用されたBANを解除する
sudo fail2ban-client set sshd unbanip 198.51.100.23

# 悪質なIPアドレスを即座にBANする
sudo fail2ban-client set sshd banip 203.0.113.99
Share: