「fail2banが入ってるから安心」は勘違い?ログ仕様変更で効かない攻撃を即BANする正しい防御術

この記事は約23分で読めます。

「VPSを借りて、SSHのポートも変えたし、鍵認証も設定した」
「念のため apt install fail2ban も実行しておいたから、これでセキュリティは万全!」
そう思って安心して夜眠りについたことはありませんか?

……ちょっと待ってください。それ、実はまったく攻撃を防げていないかもしれません。

Linuxの最新ディストリビューション(特に近年のUbuntuやDebianなど)では、OS内部でのログの出力方法や記録方式(syslog vs journald)の仕様変更が静かに進んでいます。
その結果、昔ながらの解説記事の通りに fail2ban を設定しただけでは、fail2banがログを見失って「完全な沈黙状態」に陥り、攻撃者の辞書攻撃(ブルートフォース)を横目で素通りさせているケースが多発しているのです。

この記事では、あなたのサーバーで今まさに起きているかもしれない「fail2ban沈黙の恐怖」と、攻撃者を確実に検知して即座に撃ち落とす正しい設定・検証テクニックを徹底解説します!

1. VPS起動から数分で始まる「海外からの辞書攻撃」の現実

新しいVPS(仮想専用サーバー)を契約し、グローバルIPアドレスが割り当てられた瞬間から、あなたのサーバーは世界中の自動攻撃ボット(Botnet)のターゲットになります。

「まだWebサイトも公開していないし、誰もこのIPを知らないはずだから大丈夫」という考えは通用しません。攻撃者はインターネット全体のIPアドレスを無差別にフルスキャンしており、ポートが開いているサーバーを見つけると、即座にブルートフォース(総当たり攻撃)や辞書攻撃を仕掛けてきます。

実際にログへ刻まれる「無差別アタック」の爪痕

例えば、メールサーバー(Postfix)やSSHのポートを開けている場合、/var/log/syslogjournalctl を覗いてみると、以下のような接続エラーログが1秒間に何十回も怒涛の勢いで刻み込まれているはずです。

Plaintext
# Postfix(メールサーバー)への無差別辞書攻撃の例
# Example of a brute-force dictionary attack against Postfix (mail server)
Jul 21 04:12:01 my-server postfix/smtpd[12345]: warning: unknown[81.30.98.xxx]: SASL LOGIN authentication failed: U2FsdGVkX1...
Jul 21 04:12:02 my-server postfix/smtpd[12345]: warning: unknown[81.30.98.xxx]: SASL LOGIN authentication failed: YmFzZTY0...
Jul 21 04:12:03 my-server postfix/smtpd[12346]: warning: unknown[185.220.101.xxx]: SASL LOGIN authentication failed: dGVzdDEyM...
Jul 21 04:12:05 my-server postfix/smtpd[12347]: warning: unknown[45.142.120.xxx]: SASL LOGIN authentication failed: cGFzc3dvcmQ...
  • 81.30.98.xxx185.220.101.xxx といった海外の乗っ取られた機器(IoTボットやTorノード)から、ランダムなID/パスワードの組み合わせが秒単位で叩き込まれています。

「SSHのポート番号を22から変更したから大丈夫」と思っていても、Postfix(25/587番ポート)やその他のサービスが開いていれば、攻撃者はそこを足がかりにしてシステムのリソースを喰いつぶし、認証を突破しようと試みてきます。
これらを人間が手動でIP拒否(UFW追加など)していくのは不可能です。だからこそ、攻撃パターンを自動検知してIPを遮断する fail2ban の存在が不可欠になります。

2. 「fail2banを入れたから安心」に潜む最大の落とし穴

「パッケージも入れたし、jail.localenabled = true も書いた。これで攻撃が来ても自動でBANされるはず!」
そう思って安心し、数日後に fail2ban-client status を叩いて驚愕した経験はないでしょうか?

Plaintext
# 状態を確認してみると…(Check the status...)
$ sudo fail2ban-client status postfix-sasl
Status for the jail: postfix-sasl
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     0
|  `- File list:        /var/log/mail.log
`- Actions
   |- Currently banned: 0
   |- Total banned:     0
   `- Banned IP list:

Total failed: 0 ……? ログにはあんなに攻撃が届いているのに、1件も検知されていない!?」

そう、これが「fail2ban沈黙の罠」です。実は、近年のLinux環境では以下のような「ログとfail2banのミスマッチ」が原因で、攻撃を1件も捉えられていないケースが多発しています。

罠①:ログの「出力先」がずれている(mail.log vs syslog)

ネット上の古い解説記事の多くには、メール系のログ監視について次のように書かれています。

「logpath = /var/log/mail.log を指定しましょう」

しかし、近年のUbuntu(22.04 LTSや24.04 LTSなど)やDebianでは、デフォルトで /var/log/mail.log/var/log/auth.log といったサービスごとの個別ログファイルが出力・生成されない仕様になっていることがあります。
攻撃ログは実際には /var/log/syslog に直接吐かれているのに、fail2banは存在しない(または更新されない)/var/log/mail.log を虚しく監視し続けているため、攻撃を完全にスルーしてしまうのです。

罠②:ログ取得方式(backend)の噛み合いエラー

Linuxでは、ログの管理方法が従来の「テキストファイル(rsyslog)」から「バイナリログ(systemd-journald)」へと移行しています。
これに伴い、fail2ban側でも backend = systemd を使って journald から直接ログを読み取る設定が推奨されるようになりました。しかし、ここにも大きな落とし穴があります。

  • backend = systemd にした場合:
    journald側のメタデータ(_SYSTEMD_UNIT など)と fail2ban 側のフィルタ条件が完璧に噛み合っていないと、ログが流れてきてもフィルタを素通りしてしまいます。
  • backend = auto にした場合:
    環境によっては意図しないバックエンドが選択され、テキストログの監視が行われなくなるケースがあります。

つまり、「どのファイルに(あるいはjournalに)ログが出ていて、fail2banにどの方式で監視させるか」を正しく合わせないと、fail2banは一切仕事をしてくれません。

罠③:Python 3.12環境などでの構文・フィルタ設定の不一致

さらに、OSのアップデートに伴いPythonのバージョン(Python 3.12〜)が上がると、fail2banのカスタムフィルタ(.conf ファイル)の書き方にも厳格さが求められるようになります。
インクルード設定([INCLUDES])の記述漏れや、正規表現の微妙な表記揺れによって、設定ファイルを読み込む段階でエラーを起こし、Jail(監視プロセス)自体が起動に失敗しているケースも少なくありません。
「ツールを入れた」ことと「防御が機能している」ことは別問題です。では、どうすればこの沈黙を破り、確実に攻撃者をブロックできるのでしょうか?

次章で、攻撃者を確実に撃ち落とす「正しい設定手順」をステップ・バイ・ステップで解説します!

3. 【実践】攻撃者を確実に撃ち落とす「fail2ban」完全設定手順

ここからは、実際に攻撃ログを検知し、瞬時にIPをBANするための正しい設定手順をステップ順に解説します。

STEP 1: 実際に攻撃ログがどこに吐かれているか確認する

まずは、自分のサーバーの攻撃ログが「どのファイルに」「どんなフォーマットで」記録されているかを確認します。

ターミナルで以下のコマンドを実行し、実際にログが流れているか確かめましょう。

Bash
# syslog を確認する場合(To check syslog)
sudo tail -n 20 /var/log/syslog

# または journalctl を確認する場合(Alternatively, check the logs with journalctl)
sudo journalctl -u postfix -n 20

もし /var/log/mail.log が存在しない(あるいは空っぽ)で、/var/log/syslogjournalctl 側に SASL LOGIN authentication failed などのログがリアルタイムで刻まれているなら、監視対象を /var/log/syslog に設定するのが確実です。

STEP 2: 専用カスタムフィルターを作成する

次に、fail2banに「どんな文字列を見つけたら攻撃とみなすか」を教えるフィルターを作成します。
最新のPython 3.12環境などでもエラーを起こさないよう、冒頭に [INCLUDES] 宣言を入れた構成にするのがポイントです。

/etc/fail2ban/filter.d/postfix-sasl-custom.conf を新規作成します。

Bash
sudo nano /etc/fail2ban/filter.d/postfix-sasl-custom.conf

以下の内容を貼り付けて保存します。

INI
[INCLUDES]
before = common.conf

[Definition]
# 逆引き不能(unknown)と逆引き成功(ホスト名あり)の両方の辞書攻撃にマッチ
# Match both dictionary attacks with failed reverse DNS lookups (unknown)
# and successful reverse DNS lookups (hostname present)
failregex = ^%(__prefix_line)swarning: unknown\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed:
            ^%(__prefix_line)swarning: \S+\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed:

ignoreregex =

STEP 3: jail.localの編集(backend = polling の指定)

続いて、監視ルール(Jail)を有効化します。
設定の直接書き換えを防ぐため、jail.conf ではなく /etc/fail2ban/jail.local を編集(または作成)します。

Bash
sudo nano /etc/fail2ban/jail.local

ここで最大のポイントとなるのが backend = polling の指定です。

これを指定することで、journaldのメタデータ不一致によるスルーを防ぎ、テキストログファイル(/var/log/syslog)の追記を確実にポーリング監視してくれます。

INI
[postfix-sasl]
enabled  = true
port     = smtp,465,submission,587
filter   = postfix-sasl-custom
logpath  = /var/log/syslog
backend  = polling
maxretry = 3
findtime = 600
bantime  = 86400
  • maxretry = 3: 10分(600秒)以内に3回認証失敗したらBAN
  • bantime = 86400: 攻撃IPを24時間(86400秒)完全に遮断

つぎにデータベースのパージ期間を設定します。

Bash
sudo nano /etc/fail2ban/fail2ban.conf

下の方へスクロールしていきdbpurgeageを見つけて書き換えます。

Bash
dbpurgeage = 2d

(※ Fail2ban では 1d8d のような「日(day)」単位の表記が使えます。691200 と秒数で書いてもOKですが、8d と書くのが一番スマートで確実です)

STEP 4: fail2ban-regex で事前テストを行う(★超重要)

設定を反映する前に、「本当にこのフィルターで実際のログから攻撃IPを抽出できるか?」をテストするコマンドを叩きます。これを行うことで、無駄な試行錯誤をゼロにできます。

Bash
sudo fail2ban-regex /var/log/syslog /etc/fail2ban/filter.d/postfix-sasl-custom.conf

実行後、出力結果の一番下を確認してください。

Plaintext
Results
=======
Failregex: 42 total
|- [#1] ^%(__prefix_line)swarning: unknown\[<HOST>\]: SASL ...
|  81.30.98.xxx (Sun Jul 21 04:12:01 2026)
|  185.220.101.xxx (Sun Jul 21 04:12:02 2026)
|  45.142.120.xxx (Sun Jul 21 04:12:05 2026)
...

Lines: 1523 lines, 0 ignored, 42 matched, 0 missed

STEP 5: 設定を反映し、動いているか確認する

テストでマッチすることが確認できたら、サービスを再起動して設定を適用します。

Bash
sudo systemctl restart fail2ban

数分後、ステータスを確認してみましょう。

Bash
sudo fail2ban-client status postfix-sasl

sudo fail2ban-client status sshd
Bash
Status for the jail: postfix-sasl
|- Filter
|  |- Currently failed: 1
|  |- Total failed:     2
|  `- File list:        /var/log/syslog
`- Actions
   |- Currently banned: 2
   |- Total banned:     2
   `- Banned IP list:   201.20.177.78 81.30.98.47

Status for the jail: sshd
|- Filter
|  |- Currently failed: 3
|  |- Total failed:     357
|  `- Journal matches:  _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
   |- Currently banned: 14
   |- Total banned:     18
   `- Banned IP list:   77.83.39.226 77.83.39.240 163.5.210.240 77.83.39.235 77.83.39.147 77.83.39.95 77.83.39.239 77.83.39.154 77.83.39.99 77.83.39.227 77.83.39.237 77.83.39.248 217.60.195.64 217.60.195.60

このように Banned IP list に次々と攻撃者のIPアドレスが吸い込まれていれば、完全防御システムの完成です!

【コラム / 注意点】BAN期間を伸ばすなら「自爆防止(ignoreip)」が必須!

bantime を1週間(604800秒)などの長期間に設定する場合、ご自身の接続環境をあらかじめホワイトリストに入れておくことが絶対条件です。

設定しないままタイポ(入力ミス)を3回繰り返すと、自分自身が1週間サーバーから完全締め出しを食らうことになります。

1. jail.local への記述例

/etc/fail2ban/jail.local[DEFAULT] セクションにある ignoreip に、除外したいIPやドメインを半角スペース区切りで並べて記述します。

Plaintext
[DEFAULT]
# ローカルホスト、社内/自宅LAN、固定IP、ドメイン名を半角スペース区切りで指定
# Specify localhost, internal/home LAN, fixed IP addresses, and domain names separated by spaces
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24 153.156.79.69 test-site.online
  • 127.0.0.1/8 ::1: サーバー内部通信(必須)
  • 192.168.1.0/24: LAN内のプライベートIP帯(CIDR表記)
  • 153.156.79.69: 自宅やオフィスの固定IP
  • test-site.online: Dynamic DNS(DDNS)等でIPが変わる場合のドメイン指定

2. 設定が反映されたか確認するコマンド

設定後、サービスを再起動して fail2ban-client で読み込み状況を確認します。

Bash
sudo systemctl restart fail2ban
sudo fail2ban-client get sshd ignoreip
【実行結果例】
Plaintext
These IP addresses/networks are ignored:
|- 127.0.0.0/8
|- 192.168.1.0/24
|- test-site.online
|- ::1
`- 153.156.79.69

このようにリストが表示されれば設定完了です。これで安心して強固な防衛ルールを運用できます!

4. 万が一効かない時のデバッグ手順と「応急手動BAN」

どれほど入念に設定しても、OSのマイナーアップデートや別サービスの追加によって「急に検知しなくなった」という事態は起こり得ます。
トラブルが発生した際に焦らず対処するためのデバッグ手順と、試行錯誤している間に攻撃を食らい続けないための手動BAN(緊急避難)テクニックを覚えておきましょう。

トラブル時のデバッグチェックリスト

もし fail2ban-client status を叩いて攻撃がスルーされていると感じたら、以下の順で切り分けを行います。

  1. fail2ban自体のログ(/var/log/fail2ban.log)を確認する
Bash
sudo tail -n 30 /var/log/fail2ban.log

設定ファイルの文法エラーや、ファイルの読み込み失敗(ERRORWARNING)が出ていないかチェックします。

  1. Jailが正しく起動しているか確認する
Bash
sudo fail2ban-client status

Jail list に目的の監視項目(postfix-sasl など)が表示されていない場合、jail.localenabled = true の記述漏れや構文エラーが原因です。

  1. fail2ban-regex でログの更新状態を追う ログファイルのパケットがリアルタイムで増えているか、正規表現に引っかかっているかを再度テストコマンドで確認します。

設定試行錯誤中の「応急手動BAN」コマンド

「fail2banの正規表現を調整している間にも、怒涛の辞書攻撃が届いてサーバーが重い…」という場合は、UFW(ファイアウォール)やiptablesを使って、攻撃元IPを手動で直接ブロックしてしまいましょう。

Bash
# UFWで特定の攻撃IPを今すぐ完全遮断する場合
# To immediately and completely block a specific attack IP address using UFW
sudo ufw insert 1 deny from 81.30.98.xxx to any

# 悪質なサブネット(帯域全体)をまとめて遮断する場合
# To block an entire malicious subnet (IP range) at once
sudo ufw insert 1 deny from 185.220.101.0/24 to any

💡 コマンドのポイント:
insert 1 を付けることで、既存の allow(許可ルール)よりも優先度の高い「最優先ブロックルール」として挿入できます。原因究明までの応急処置として非常に有効です。

5. まとめ:防御システムは「動いているか」まで確認して初めて意味を成す

セキュリティ対策において最も危険なのは、「対策ツールを入れたことで満足し、実際には機能していないことに気づかない状態」です。
今回解説した通り、近年のLinux環境ではログ出力の仕様(syslog vs journald)やPythonの動作仕様の変更に伴い、従来の解説通りの設定では fail2ban が沈黙してしまうケースが後を絶ちません。

  • apt install して安心せず、必ず status コマンドで BAN 実績を確認する
  • fail2ban-regex を使って、自分の環境の実際のログと正規表現をマッチングテストする
  • ログの追尾が不安定な場合は backend = polling でテキストログを直接監視させる

サーバー運用の基本は、「設定して終わり」ではなく「実際に攻撃を防げているかまで検証すること」です。
ぜひ今すぐご自身のVPSにログインし、fail2ban が本当にあなたのサーバーを守ってくれているかチェックしてみてください!

コメント

タイトルとURLをコピーしました