手動IPブロックの課題とIP Setsの威力
大規模なWebシステムの管理を始めたばかりの頃、私は数千ものIPアドレスからブルートフォース攻撃を受けるという事態に直面しました。当時は、firewall-cmd --add-rich-ruleをひたすら打ち込み、一つずつアドレスをブロックしていました。その結果、ルールリストは膨大になり、FirewallをリロードするたびにサーバーのCPU使用率が100%に跳ね上がり、正規ユーザーのリクエストに深刻な遅延が発生してしまいました。
この経験から学んだのは、数百、数千のIPを個別のルールで管理すべきではないということです。そこで最適なソリューションとなるのがIP Setsです。このツールを使えば、数千のIPアドレスやネットワーク範囲(サブネット)を一つのリストにまとめることができます。1,000個のルールを順番にチェックする代わりに、Firewallはハッシュテーブル(Hash Table)構造を利用して一度のチェックで済ませます。この時の処理速度はO(1)であり、ほぼ瞬時です。
CentOS Stream 9ではバックエンドがnftablesに変更されましたが、Firewalld IP Setsは依然として非常に強力です。頻繁に攻撃を仕掛けてくる国からのトラフィックを徹底的に遮断したい場合、これは避けては通れない技術です。
インストールと環境準備
CentOS Stream 9には通常Firewalldがプリインストールされていますが、サービスが安定して動作しているか確認しましょう。また、迅速な確認操作のためにipsetパッケージもインストールしておきます。
# システムを素早く更新
sudo dnf update -y
# 必要なツールをインストール
sudo dnf install firewalld ipset -y
# Firewalldを有効化
sudo systemctl enable --now firewalld
# 動作ステータスを確認
sudo firewall-cmd --state
CentOS 7から9へシステムを移行した際、コマンドの構造自体に大きな変更はないことに気づきました。しかし、背後で動作する nftables の最適化により、バージョン9でのIP Setsの処理パフォーマンスは明らかに向上しています。
FirewalldでのIP Sets詳細設定
ステップ1:新しいIP Setを作成する
まずはブラックリストを格納するための「カゴ」を作成します。ここでは名前をblacklist_ipsとします。最も一般的なIP Setのタイプはhash:netで、個別のIPとCIDR形式のネットワーク範囲の両方をサポートしています。
sudo firewall-cmd --permanent --new-ipset=blacklist_ips --type=hash:net
パラメータの説明:
--permanent: 再起動後も設定を永続化します。--new-ipset: リストに名前を付けます。--type=hash:net: ネットワーク範囲(例:192.168.1.0/24)を保存するためのデータ型です。
ステップ2:リストにIPを追加する
作成したセットに、不審なIPやスパム送信元のネットワーク範囲を手動で追加できます。
# 特定のIPをブロック
sudo firewall-cmd --permanent --ipset=blacklist_ips --add-entry=1.2.3.4
# ネットワーク範囲全体をブロック
sudo firewall-cmd --permanent --ipset=blacklist_ips --add-entry=192.168.100.0/24
リストが数百件に及ぶ場合は、手入力は現実的ではありません。list.txt(1行に1IP)に保存し、bashのループを使ってインポートしましょう。
for ip in $(cat list.txt); do
sudo firewall-cmd --permanent --ipset=blacklist_ips --add-entry=$ip
done
ステップ3:ブロックルールを有効化する
リストを作成しただけでは、Firewallはまだ何も行いません。Firewalldに対して「blacklist_ipsに含まれるIPからのアクセスがあれば、即座にDROPせよ」というリッチルール(rich rule)を追加する必要があります。
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source ipset="blacklist_ips" drop'
最後に、すべての変更を有効にするためにリロードします。
sudo firewall-cmd --reload
国単位でIPをブラックリスト化する方法
これは非常に効果的な手法です。例えば、サーバーが特定の地域のユーザーのみを対象としている場合、関係のない国からのトラフィックを遮断することで、自動スキャンによる攻撃リスクを80〜90%削減できます。
IPDenyのデータを使用すれば、スクリプトでこのプロセスを自動化できます。
# 特定の国(例:中国 - コード 'cn')用のIP Setを作成
sudo firewall-cmd --permanent --new-ipset=country_block --type=hash:net
# 最新のIPレンジリストをダウンロード
curl -O http://www.ipdeny.com/ipblocks/data/countries/cn.zone
# 数千のネットワーク範囲をSetにインポート
for range in $(cat cn.zone); do
sudo firewall-cmd --permanent --ipset=country_block --add-entry=$range
done
# DROPルールを適用
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source ipset="country_block" drop'
sudo firewall-cmd --reload
注意:5,000〜8,000のネットワーク範囲をインポートする際、1〜2分かかる場合があります。しかし、一度読み込んでしまえば、パケットのフィルタリングによってサーバーがラグ(遅延)を起こすことはありません。
確認とモニタリング
システムが正しく動作しているか確認するために、以下のコマンドを活用してください。
1. 既存のIP Setをリスト表示する:
sudo firewall-cmd --get-ipsets
2. Set内のIPリストを表示する:
sudo firewall-cmd --ipset=blacklist_ips --get-entries
3. 特定のIPがブロックされているか素早く確認する:
ipset test blacklist_ips 1.2.3.4
プロフェッショナルな管理のコツ
- RejectではなくDropを使う: 広範囲をブロックする場合、
dropを使用して静かに接続を切断します。rejectは攻撃者に拒否応答を返してしまうため、無駄な帯域幅を消費します。 - 設定のバックアップ: すべてのIP Setは
/etc/firewalld/ipsets/にXMLファイルとして保存されます。このファイルを新しいサーバーにコピーするだけで、設定の移行が完了します。 - 自動更新: 国別のIP範囲は常に変化します。毎週Cronjobを設定して、zoneファイルを再ダウンロードし、リストを自動更新するように設定することをお勧めします。
IP Setsを使いこなせるようになったことで、インターネットからの攻撃に対しても自信を持って対処できるようになりました。わずか数行のコマンドで、パフォーマンスを犠牲にすることなく、CentOS Stream 9サーバーに強固な「盾」を構築することができます。

