Linuxのipsetコマンドで大量IPを効率管理する方法|iptables・firewalldと連携してDDoS対策も

運営:リナックスマスター.JP(代表 宮崎智広)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Linuxtips > セキュリティ > Linuxのipsetコマンドで大量IPを効率管理する方法|iptables・firewalldと連携してDDoS対策も
「攻撃元のIPが次々と変わるたびにiptablesのルールを1つずつ追加していたら、ルール数が数百件を超えてサーバーのパフォーマンスが下がってしまった」
こういった経験をしたことはありませんか。

iptablesはパケット1つを処理するたびにルールを上から順に照合します。ルール数が増えるほど照合コストが増加し、高トラフィック環境ではCPUへの負荷が無視できなくなります。

この記事では、大量のIPアドレスを「セット」としてまとめて管理できるipsetコマンドを解説します。RHEL 9系・Ubuntu 24.04 LTSを想定環境として説明します。iptablesやfirewalldと組み合わせることで、ルール数を最小限に保ちながら数万件規模のIPアドレスを効率よくフィルタリングできます。

この記事のポイント

・ipsetはIPアドレス・ネットワークをハッシュセットで管理し、iptablesのルール爆発を防ぐ
・`ipset create`でセット作成後、`ipset add`でIPを追加し、iptablesの`-m set --match-set`で参照する
・firewalldとの連携は`firewall-cmd --ipset`で行い、既存の管理フローを壊さずに導入できる
・再起動後も設定を維持するには`service ipset save`またはsystemdユニットで自動復元する


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

ipsetとは何か|iptablesの弱点を補う仕組み

iptablesは1つのマッチ条件に対して1つのルールを書く設計です。10個のIPをブロックするには10本の-A INPUT -s <IP> -j DROPが必要で、ルールが増えるほどカーネルはパケット1つにつきすべてのルールを上から照合します。

ipsetはこの問題を解消するためのLinuxカーネルモジュールです。IPアドレスやネットワーク(CIDR)、ポート番号などをハッシュテーブル構造のセットとして管理します。iptablesからセット名で参照するだけで、セットの中身が何万件あっても高速な照合が可能です。

主な使いどころ:
・DDoS対策で攻撃元IPをまとめてブロック
・国単位の地理的IPブロック
・許可リスト(ホワイトリスト)の管理
・不正アクセスのログから自動的にIPを登録してブロック

ipsetのインストールと基本的な使い方

1. インストール

RHEL 9系 / Rocky Linux / AlmaLinuxの場合:

# dnf install ipset ipset-service

Ubuntu 24.04 LTS の場合:

# apt install ipset

インストール後、バージョンを確認します:

# ipset version

出力例(環境により異なります):

ipset v7.11, protocol version: 7

2. セットを作成する

ipset create <セット名> <セットタイプ>でセットを作成します。よく使うセットタイプは以下の3つです:

・hash:ip — 個別IPアドレスを管理するセット
・hash:net — CIDRネットワークアドレスを管理するセット
・hash:ip,port — IPアドレスとポートの組み合わせを管理するセット

ブロックリスト用のセットを作成する例:

# ipset create blocklist hash:ip

3. IPアドレスを追加・確認・削除する

# ipset add blocklist 203.0.113.10 # ipset add blocklist 203.0.113.20 # ipset add blocklist 198.51.100.0/24

セットの内容を確認します:

# ipset list blocklist

出力例(環境により異なります):

Name: blocklist Type: hash:ip Revision: 4 Header: family inet hashsize 1024 maxelem 65536 Size in memory: 312 References: 0 Number of entries: 3 Members: 203.0.113.10 203.0.113.20 198.51.100.0/24

IPアドレスを削除するにはipset delを、セット自体を削除するにはipset destroyを使います:

# ipset del blocklist 203.0.113.10 # ipset destroy blocklist

iptablesと組み合わせる|-m set --match-set の書き方

ipsetのセットはiptablesの-m set --match-setオプションで参照します。

# iptables -I INPUT -m set --match-set blocklist src -j DROP

オプションの意味:
・-m set — ipsetモジュールを使用する
・--match-set blocklist — セット名「blocklist」を参照する
・src — 送信元(source)IPで照合する(宛先の場合はdst)

現在のINPUTチェーンのルールを確認します:

# iptables -L INPUT -v -n --line-numbers

iptablesのルールが1行で済むため、セットに10万件のIPが入っていても照合ルール数はIPを個別に書いた場合と変わりません。Linuxサーバーの安全な構築・運用を体系的に学びたい場合は、Linux Masterセミナーで実務に直結した設計の考え方を身につけることができます。

firewalldとipsetを連携させる方法

RHEL 9系ではiptablesを直接操作するよりfirewalldを使うのが標準です。firewalld 0.6以降はipsetをネイティブにサポートしています。

1. ipsetをfirewalld経由で作成する

# firewall-cmd --permanent --new-ipset=blocklist --type=hash:ip # firewall-cmd --reload

2. IPをfirewalld経由で追加する

# firewall-cmd --permanent --ipset=blocklist --add-entry=203.0.113.10 # firewall-cmd --permanent --ipset=blocklist --add-entry=198.51.100.0/24 # firewall-cmd --reload

3. セットをゾーンのブロックルールに適用する

# firewall-cmd --permanent --zone=public --add-rich-rule='rule source ipset=blocklist drop' # firewall-cmd --reload

セットの内容を確認します:

# firewall-cmd --ipset=blocklist --get-entries

firewalldで作成したipsetの設定ファイルは/etc/firewalld/ipsets/配下にXML形式で保存されます。--permanentをつけて操作した場合は再起動後も設定が引き継がれます。

ipsetの永続化|再起動後も設定を維持する

ipsetコマンドで直接作成したセットは、再起動すると消えます。永続化の方法は環境によって2通りあります。

方法1: ipset-service(RHEL系)

RHEL系ではipset-serviceパッケージに含まれるsystemdサービスを使います:

# systemctl enable --now ipset

現在のセットを/etc/sysconfig/ipsetへ保存するには:

# service ipset save # または # ipset save > /etc/sysconfig/ipset

次回起動時にipset.serviceが自動復元します。

方法2: ipset saveとsystemdユニット(Ubuntu・汎用)

ipset-serviceがない環境(Ubuntuなど)では、設定ファイルとsystemdユニットで対応します:

# ipset save > /etc/ipset.conf

次の内容で/etc/systemd/system/ipset-restore.serviceを作成します:

[Unit] Description=ipset restore Before=network-pre.target Wants=network-pre.target [Service] Type=oneshot ExecStart=/sbin/ipset restore -f /etc/ipset.conf ExecStop=/sbin/ipset save -f /etc/ipset.conf RemainAfterExit=yes [Install] WantedBy=multi-user.target

# systemctl daemon-reload # systemctl enable ipset-restore

実務活用例|SSH不正ログイン元を自動ブロックするスクリプト

SSHへの不正ログイン試行をjournalctlで検出し、攻撃元IPを自動的にipsetに追加するシェルスクリプトの例を示します。

#!/bin/bash # SSH不正ログイン元IPをipsetのblocklist(hash:ip)に追加する # このスクリプトはcronで定期実行する IPSET_NAME="blocklist" THRESHOLD=5 # セットが存在しない場合は作成 ipset list ${IPSET_NAME} > /dev/null 2>&1 || ipset create ${IPSET_NAME} hash:ip # 直近1時間のSSH失敗ログからIPを集計し、THRESHOLD回以上の攻撃元を追加 journalctl -u sshd --since "1 hour ago" --no-pager 2>/dev/null \ | grep "Failed password" \ | awk '{print $(NF-3)}' \ | sort | uniq -c | sort -rn \ | awk -v threshold=${THRESHOLD} '$1 >= threshold {print $2}' \ | while read ip; do ipset test ${IPSET_NAME} "${ip}" > /dev/null 2>&1 \ || ipset add ${IPSET_NAME} "${ip}" done

このスクリプトをcronに登録する例(1時間ごとに実行):

0 * * * * /usr/local/sbin/auto-blocklist.sh

ポイント:
・ipset testで既存エントリの重複追加を防いでいます
・THRESHOLDの値は環境に合わせて調整してください(上記は5回)
・スクリプト実行前に、対象のipsetとiptables/firewalldルールが設定済みであることを確認してください

トラブルシュート|よくあるエラーと対処法

「ipset: Kernel and userspace incompatible」

カーネルのipsetモジュールとipsetコマンドのバージョンが一致していない場合に発生します。カーネルモジュールを明示的にロードします:

# modprobe ip_set # modprobe ip_set_hash_ip

解消しない場合はパッケージを更新して再起動します:

# dnf update ipset kernel # reboot

「Set cannot be destroyed: it is in use by a kernel component」

iptablesのルールがセットを参照した状態でセットを削除しようとすると発生します。先にiptablesのルールを削除してからセットを削除します:

# iptables -D INPUT -m set --match-set blocklist src -j DROP # ipset destroy blocklist

「Hash is full, cannot add more elements」

セットの上限(デフォルトはmaxelem 65536)に達しています。セット作成時にmaxelemを大きく設定します:

# ipset create blocklist hash:ip maxelem 1000000

既存セットの上限を変更するには、セットを一度保存・削除・再作成します:

# ipset save > /tmp/ipset-backup.conf # ipset destroy blocklist # ipset create blocklist hash:ip maxelem 1000000 # grep -v "^create blocklist" /tmp/ipset-backup.conf | ipset restore

「firewall-cmd: ERROR: 'blocklist' not found」

firewalldが管理するipsetと、ipsetコマンドで直接作成したセットは別物です。firewalldで使うipsetは必ずfirewall-cmd --permanent --new-ipsetで作成し、/etc/firewalld/ipsets/配下で管理します。

本記事のまとめ

やりたいこと コマンド
セットを作成する(個別IP用) ipset create blocklist hash:ip
セットを作成する(CIDR用) ipset create netblock hash:net
IPを追加する ipset add blocklist 203.0.113.10
セットの内容を確認する ipset list blocklist
iptablesで送信元IPをブロック iptables -I INPUT -m set --match-set blocklist src -j DROP
firewalldでipsetを作成 firewall-cmd --permanent --new-ipset=blocklist --type=hash:ip
firewalldでIPを追加 firewall-cmd --permanent --ipset=blocklist --add-entry=203.0.113.10
設定を保存する(RHEL系) service ipset save
セットの上限を増やして再作成 ipset create blocklist hash:ip maxelem 1000000
iptablesのルール数が増えてCPU負荷が上がり始めたときや、大量の不正アクセス元IPを一括ブロックしたいとき、ipsetは即戦力になります。DDoS対策・不正アクセス防止の実務設計をより体系的に身につけたい場合は、Linuxサーバー運用の現場に沿ったカリキュラムで学べる機会もぜひ検討してみてください。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Linux Master Pro Seminarでは、セキュリティ設定・ファイアウォール設計・サービス公開まで、実機ハンズオンで体系的に習得できます。
>> セミナー詳細・お申込みはこちら

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録

運営

リナックスマスター.JP(代表 宮崎智広)

株式会社イーネットマーキュリーが運営するLinux教育サイトです。代表の宮崎智広は現役のLinuxサーバー管理者として20年以上の実務経験を持ち、累計3,100名以上のエンジニアを指導してきました。実践型のLinuxセミナーや無料マニュアルの配布を通じてLinux人材の育成に取り組んでいます。