firewalld + ipset でアクセス制限

「CentOS 7」環境の「firewalld」で特定の国からのアクセスを拒否する設定を行ったところ、ルールが4000~5000とかなり多くなってしまいました。

その結果「firewalld」の動作がかなり重くなってしまい、良い方法を色々と調べてみたところ「ipset」と組み合わせて使用することで幸せになれるという情報が見つかりましたので、導入した際の手順についてまとめました。

ipsetとは

IPアドレスやネットワークアドレス、ポート番号、インターフェイス名などを組み合わせて管理することができるユーティリティになります。

「firewalld」で一つ一つルールを追加するよりも、格段にパフォーマンスも向上します。

ipsetインストール

まずは「yum」で「ipset」をインストールします。

# yum install ipset

セットの作成

「ipset」を使用するには、まずセット(ポリシー名みたいなもの)作成してから、そこにネットワークアドレスやIPアドレス等を追加していく必要があります。

セットを作成するためコマンドは下記の通りとなります。

ipseet create セット名 タイプ名 オプション

セット名

セット名はどのようなルールを管理しているのかが分かりやすい名前を設定します。

今回はアクセスを禁止するネットワークアドレスをまとめて管理するため「BLACKLIST」と付けることにします。

タイプ名

作成するセットの種類を指定します。

指定できるタイプは色々とあるのですが、今回使用するタイプはネットワークアドレスを管理するための「hash:net」を指定します。

タイプ一覧

指定できるタイプについて簡単にまとめて見ました。

タイプ 管理する情報
hash:ip hashを使用してIPアドレスを管理
hash:net hashを使用してネットワークアドレスを管理
hash:ip,port hashを使用してIPとポート番号を管理
hash:net,port hashを使用してネットワークアドレスとポート番号を管理
hash:ip,port,ip hashを使用してIPとポート番号の2つを管理
hash:ip,port,net hashを使用してIPとポート番号とネットワークアドレスの3つを管理
hash:net,iface hashを使用して、ネットワークアドレスとNICの2つを管理
bitmap:ip IPアドレスを管理
オプションでrange指定が必要
bitmap:ip,mac IPアドレスとMACアドレスの管理
オプションでrange指定が必要
bitmap:port ポート番号を管理
オプションでrange指定が必要
list:set 複数のセットを管理することができる

オプション

今回はすべてデフォルト設定でいきますので、特にオプションの指定は行いません。

オプション一覧

「ipset create」でセット作成する際に使用できるオプションの一覧です。

オプション 説明 使用可能タイプ
family inet(IPv4)かinet6(IPv6)を設定
デフォルトはinet
IPを使用するタイプ全般
hashsize ハッシュのサイズ
デフォルトは1024
hashを使用するタイプ全般
maxelem 登録できるルールの数
デフォルトは65536
hashを使用するタイプ全般
netmask ネットマスクを指定(1-31) bitmap:ip
hash:ip
range IPやポート番号の範囲を指定 bitmap系のタイプで使用(必須)
timeout セットの有効期限を設定
デフォルトは無制限(0)
全てのタイプで使用可能

セット作成例

今回作成する「BLACKLIST」という名前のセットには、ネットワークアドレス登録するのでタイプは「hash:net」を指定して作成します。

# ipset create BLACKLIST hash:net

ネットワークアドレス追加

セットの作成が完了しましたら、「ipset add」コマンドでネットワークアドレスを追加していきます。

ipset add セット名 ネットワークアドレス/ネットマスク

追加例

先ほど作成したセットである「BLACKLIST」にネットワークアドレスを追加していきます。

# ipset add BLACKLIST 192.168.0.0/24
# ipset add BLACKLIST 192.168.2.0/24
追加確認

セットに登録された情報は下記のコマンドで確認することが出来ます。

ipset list セット名

先ほど実際に登録した内容を確認してみます。

# ipset list BLACKLIST
Name: BLACKLIST
Type: hash:net
Revision: 3
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 16848
References: 0
Members:
192.168.0.0/24
192.168.2.0/24

登録したネットワークアドレスが確認できました。

firewalldと連携

「ipset」の準備が出来たので、次に「firewalld」との連携設定を行っていきます。

連携には「firewall-cmd」の「--direct」オプションを使用して設定を行っていきます。

書式

firewall-cmd [--permanent] --direct --add-rule [ipv4|ipv6] テーブル名 チェイン 優先順位 -m set --match-set ipsetセット名 src -j DROP

作業時の注意点

「firewalld」の設定を行う場合は十分に注意して行ってください。

設定を失敗すると、対象サーバに接続することが出来なくなってしまう場合もあります。

設定例

今回は外部からの接続対してのルールを設定するので、テーブルは「filter」を、チェインは「INPUT」を指定しています。

# firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -m set --match-set BLACKLIST src -j DROP
# firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -m set --match-set BLACKLIST src -j DROP

ここで設定した内容は「INPUT_direct」チェインに登録されます。

設定ファイル

「--direct」オプションで設定した内容は「/etc/firewalld/direct.xml」に保存されます。

direct.xml内容
<?xml version="1.0" encoding="utf-8"?>
<direct>
  <rule priority="0" table="filter" ipv="ipv4" chain="INPUT">-m set --match-set BLACKLIST src -j DROP</rule>
</direct>

設定確認

「iptables -L INPUT_direct -v」コマンドで「INPUT_direct」チェインの設定を確認して、「match-set」の部分に「ipset」で作成したセットが設定されていることを確認します。

INPUT_directチェイン確認
# iptables -L  INPUT_direct -v
Chain INPUT_direct (1 references)
 pkts bytes target     prot opt in     out     source     destination
    0     0 DROP       all  --  any    any     anywhere   anywhere   match-set BLACKLIST src
INPUTチェイン確認

次に「INPUT」チェインに「INPUT_direct」チェインが登録されていることを確認してください。

# iptables -L  INPUT -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source     destination
  432 42740 ACCEPT     all  --  any    any     anywhere   anywhere      ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     all  --  lo     any     anywhere   anywhere
  491 48989 INPUT_direct  all  --  any    any  anywhere      anywhere
  491 48989 INPUT_ZONES_SOURCE  all  --  any    any    anywhere      anywhere
  491 48989 INPUT_ZONES  all  --  any    any     anywhere            anywhere
    0     0 ACCEPT     icmp --  any    any     anywhere      anywhere
  491 48989 REJECT     all  --  any    any     anywhere      anywhere   reject-with icmp-host-prohibited

両方とも確認できましたら、「ipset」と「fireawalld」の連携は完了です。

ipset自動作成

「ipset」と「firewalld」の連携が完了しましたら、次に「ipset」に作成したセットを自動作成する設定を行っていきます。

「ipset」はメモリ上にセット内容を格納しているため、サーバを再起動したりすると内容が削除されてしまいます。

そのため「firewalld」の起動前に「ipset」のセットを作成して、セットにルールを追加するという作業が必要になるのですが、サーバの再起動毎に手動で作業を行うのは現実的ではないので、自動的にセットを作成するためのスクリプトを作成していきます。

ipset データセーブ格納ディレクトリ作成

まずは、データ保存用のディレクトリを作成します。

# mkdir /etc/ipset

セット内容保存

現在の「ipset」の情報は下記の方法で保存することが出来ます。

ipset save > ファイル名

情報の保存

「BLACKLIST」というファイルに「ipset」のセット情報を保存していきます。

# ipset save > /etc/ipset/BLACKLIST
リストア方法

保存した情報は「ipset restore」コマンドでリストアすることができます。

ipset restore < ファイル名

ipset作成スクリプト

サーバ起動時や、「firewalld」の再起動時に自動的に「ipset」のセットを作成するために、「ipset_create.sh」というスクリプトを作成します。

※スクリプトの名前はお好きな名前でかまいません。

# vi /etc/ipset/ipset_create.sh

スクリプト内容

「ipset destroy」で既存のセット情報があればそれを削除して、その後「ipset restore」でバックアップした情報からセットを作成するという動作をします。

#!/bin/bash

IPSET=/sbin/ipset
DIR=/etc/ipset
CONF=BLACKLIST

cd $DIR
$IPSET destroy
$IPSET restore < $CONF

パーミッション設定

作成したスクリプトのパーミッションを設定します。

# chmod 744 ipset_create.sh

スクリプト動作確認

スクリプトの作成が終わりましたら、次に動作試験を行っていきます。

firewalldとの連係解除

「firewalld」と連携していると「ipset destroy」や「ipset restore」が行えないため、一度「firewalld」との連携を解除します。

# firewall-cmd --direct --remove-rule ipv4 filter INPUT 0 -m set --match-set BLACKLIST src -j DROP

スクリプト動作試験

「firewalld」との連携が解除されましたら、「ipset destoy」でセットを削除してからスクリプトを実行しセットがリストアされることを確認してください。

既存のセット削除と削除確認
# ipset destroy
# ipset list
スクリプト実行
# sh -x /etc/ipset/ipset_create.sh
# ipset list

スクリプトの動作に問題が無ければ、「firewalld」が起動する前に「ipset」のセット作成スクリプトを実行して、セットを作成するように設定を行っていきます。

firewalldsystemd管理用スクリプト変更

「firewalld」が起動する前にipsetのセットが作成されている必要があるため、「firewalld」のsystemd管理用スクリプト(/usr/lib/systemd/system/firewalld.service)を編集していきます。

# cp -p /usr/lib/systemd/system/firewalld.service /usr/lib/systemd/system/firewalld.service_yyyymmdd
# vi /usr/lib/systemd/system/firewalld.service

変更内容

[Service]セクションに「ExecStartPre」を設定すると、起動前に実行するスクリプトを指定できるので「ipset」作成用のスクリプト(/etc/ipset/ipset_create.sh)を指定します。

[Service]
EnvironmentFile=-/etc/sysconfig/firewalld
ExecStartPre=/etc/ipset/ipset_create.sh      <-----追加
ExecStart=/usr/sbin/firewalld --nofork --nopid $FIREWALLD_ARGS
ExecReload=/bin/kill -HUP $MAINPID

動作確認

「/usr/lib/systemd/system/firewalld.service」の編集が完了しましたら、「firewalld」と「ipset」の連携試験を行っていきます。

firewalld再起動テスト

「ipset」の中身を空にしてから「firewalld」を再起動して「ipset」と連携できているか確認します。

ipset flush

一旦「ipset」のセット「BLACKLIST」の情報を削除します。

# ipset destroy
# ipset list

「firewalld」を再起動して、「ipset」と連携できているか確認します。

# systemctl restart firewalld

ipset確認

「ipset」のセット登録情報を確認します。

# ipset list BLACKLIST

iptable設定状況確認

「INPUT」と「INPUT_direct」チェインの内容を確認し、それぞれ登録されていることを確認してください。

# iptables -L  INPUT_direct -v
Chain INPUT_direct (1 references)
 pkts bytes target     prot opt in     out     source     destination
   14   612 DROP       all  --  any    any     anywhere   anywhere   match-set BLACKLIST src
# iptables -L  INPUT -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source     destination
  171 15112 ACCEPT     all  --  any    any     anywhere   anywhere   ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     all  --  lo     any     anywhere   anywhere
   41  2480 INPUT_direct  all  --  any    any     anywhere   anywhere
    8  1032 INPUT_ZONES_SOURCE  all  --  any    any     anywhere   anywhere
    8  1032 INPUT_ZONES  all  --  any    any     anywhere   anywhere
    0     0 ACCEPT     icmp --  any    any     anywhere   anywhere
    8  1032 REJECT     all  --  any    any     anywhere   anywhere   reject-with icmp-host-prohibited

サーバ再起動試験

「firewalld」の再起動試験で問題がなければ大丈夫だと思いますが、念のためにサーバの再起動試験が行えるのであれば実施したほうが安心です。

もし、今すぐにサーバの再起動が行えない場合は、次回サーバ再起動時に忘れずに確認を行ってください。

以上で作業完了となります。

国別のIPリスト作成方法

特定の国からの通信を遮断したい場合、その国に配布されているIPアドレスの一覧を調べる必要があります。

IPアドレスを管理している各団体のページから情報をダウンロードしてきて、自分で必要な情報を抽出するという方法もありますが、それは面倒なので私はいつも下記のサイトのお世話になっています。

https://ipv4.fetus.jp/

IPアドレスの一覧が欲しい国を選択すると、その国に割り当てられているIPアドレスの一覧を表示してくれます。

また、画面右側の「Download」の「プレインテキスト」からテキストで情報をダウンロードすることができるので、これを元にIPセットを作成すると良いでしょう。

ちなみに、私はセットに登録する際には下記のようなスクリプトを使用して登録しています。

※登録するセットは事前に作成しておいてください。

#!/bin/bash

LIST="ファイル名"
SET="セット名"
COM="/sbin/ipset add"

while read line; do
        $COM $SET $line
done < $LIST

コメント

  1. sushi より:

    tamohikoさん suhsiです。

    バーチャルホストできました\(*T▽T*)/
    本当にありがとうございます!!!
    めちゃめちゃ感動ですよ!!!
    親身になって優しくしていただいて
    なんとお礼を言ったらいいかヽ(^◇^*)/

    tamohiko さん の ご回答を何度も
    読み直して、わたしの間違っているところを
    調べなおしたんですね、そしたら
    「あれ?バーチャルホストにしたいドメインの」
    DNS設定ってしっかりなってるのかな?と思って

    メインのドメインの方は、CENTOS7にインストールした
    DICEでやっているんですけど、
    サブドメインは未設定だったんですね
    (。-人-。) オ、オユルシヲ・・・

    それで、バーチャルホストにしたい方のアドレスを
    MyDNS のオンラインサービスDNSでやることにしたんです。
    そして、/etc/hosts で名前解決もして、
    そしたら大成功ですよ!
    本当にありがとうございました^^

    超うれしいです。本日、さらに一段と自宅サーバーが
    大好きになりました^^

    なぜBINDの設定をしたかですけど、
    以前に、ヤフー知恵袋に
    この件を相談したときに、BINDを設定しないとダメだよ!
    と回答されて、それで設定したんですね。
    私の場合、これは関係なかったんですね、それか、
    自分で、DNSサーバーを作る人はこれが必要だったのかな?

    直接のメールやり取り!喜んで^^
    ぜひぜひ、弟子にしてください!

    tamohikoさんから、バーチャルホスト、
    ウェブアライザー、ファイヤーウォールdの使い方を
    教わって、これで超楽しい自宅サーバーライフが
    はじまりますね!
    本当にありがとうございました。直接のメール
    お待ちしてまーすヽ(*^^*)ノ

  2. sushi より:

    tamohikoさん

    こんばんわ。
    tamohikoさんは、すごく優しいですね。
    ipsetについて、すごくわかりやすく、
    そして丁寧に教えていただいて
    うれしいですウゥゥ((´;ω;`)
    本当にありがとうございます。
    さっそくやってみます!

    バーチャルホストについても、ありがとうございます。

    私は、CentOS7 の apacheです。
    ドメインは3つ持ってます。
    けど、問題なく使えているのは、無料で取得した
    hogehoge.dip.jp というドメインだけです。

    +——————————+
    ieServerで取得無料ドメイン1つ目
    hogehoge.dip.jp

    ieServerで取得無料ドメイン2つ目
    hogevirtual.jpn.ph

    VALUE DOMAINで買った有料ドメイン
    hogehoge.site
    +——————————+

    の計3つです。

    インターネット回線は「ZAQ」という会社で
    マンションに備え付けの無料インターネットで、
    これが固定IPに非対応のようなんです。

    >>
    また、この環境であればDDNS環境での運用になるのかなと思うのですが、
    こちらの方の設定は完了していますか?
    >>

    一応、以下のサイト様を参考にさせてもらって、
    hogehoge.dip.jp(無料ドメイン1)これ1つだけなら
    問題なく表示はできています。
    https://centossrv.com/domain-ieserver.shtml

    あと、BINDの設定もできました。nslookupとかも動作します。
    https://centossrv.com/bind.shtml
    ただ、私の2つ目のドメインの設定方法が間違っているようで
    hogevirtual.jpn.ph(無料ドメイン2)
    が表示されないんです。(T^T)

    サーバーの プライベートIPは 192.168.0.12で
    固定IPは 118.87.xxx.xxx  です。

    ネームサーバーだとか、ゲートウェイとか
    DNS とか どのファイルに、どの情報を何の数値を入力するか、
    それがよく理解できていなくて、1カ月苦しんでます><

    上記の私と同じような環境の方で
    バーチャルホストの設定されている方がいないか、
    ずっとネット上でいろいろ探しているんですけど、
    皆さん、有料ドメインだったり、固定IPだったりして、
    その場合、どこをどう自分に合わせて変更したら
    いいかわからなくて。。。

    tamohikoさん
    相談に乗っていただいて本当にありがとうございます。
    ( ノД`)

    • tamohiko より:

      sushiさん

      お返事ありがとうございます。

      バーチャルホストの件について、もう少し確認させてください。

      (1)問題点の確認

      現時点での問題点は下記2点だと認識しているのですがあっていますか?

      ・バーチャルホストで表示できないドメインがある
      ・名前解決が出来ないドメインがある

      (2)バーチャルホストの動作確認

      まずはバーチャルホストの設定をがあっているかを確認したいので、、
      hostsにIPとホスト名を設定して3ドメインとも名前解決が出来るように設定してみてください。

      192.168.0.12 hogehoge.dip.jp
      192.168.0.12 hogevirtual.jpn.ph
      192.168.0.12 hogehoge.site

      設定するファイルは、クライアントがWindowsならば「C:Windows\System32\drivers\etc\hosts」でCentOSの場合は「/etc/hosts」となります。

      これで、名前解決が出来るようになると思いますので、Webブラウザでそれぞれのドメインにアクセスしてみてください。
      もし、これでもWebサイトにアクセスできない場合は、その際に出たメッセージを教えてください。

      (3)DDNSの登録について
      3ドメインはすべてDiCEを使用して「ieServer」と「バリュードメイン」のDDNSにIPの自動更新設定を行ったが、
      「hogehoge.dip.jp」だけしか名前解決が出来ないという認識で良いでしょうか?

      > あと、BINDの設定もできました。nslookupとかも動作します。
      > https://centossrv.com/bind.shtml
      > ただ、私の2つ目のドメインの設定方法が間違っているようで
      > hogevirtual.jpn.ph(無料ドメイン2)
      > が表示されないんです。(T^T)

      BINDは何のために使用しているのでしょうか?
      サイトの方を見てみたのですが、いまいちよくわかりませんでしたので…

      あと、コメント欄でのやり取りだと読みづらくなってしまうので
      よろしければ、直接メールでやり取りさせて頂けますか?

      もしよろしければ、その旨コメント頂けますでしょうか。

      私の方からメールさせていただきますので、よろしくお願いいたします。

  3. sushi より:

    tamohikoさん、

    sushiです。

    ipsetの記事読ませていただきました。さすがですね!
    返信が遅くなってすみません。

    tamohikoさんのおっしゃるとおり、あの
    大量のIPでしたので、
    スクリプトを使って所定の書式を作ってやっていたのですが、
    そのスクリプトを作るのも、わたくし超初心者でして、
    やっとのやっとだったんですね^^;
    最近ようやくその準備ができたところだったんです^^;

    でも、なるほど、それだとfirewalldの動作に影響がでてくるんですね。
    「ipset」というものを使ってですか、とても勉強になりました^^
    さらに深く調べていただけるなんて、ミシュラン星 もう一つ追加
    すばらしいですよ!!!

    あの・・・お言葉に甘えて、2つお願いがあるのですが、

    1つめは、
    記事の一番最後の”スクリプト”の記述なんですが、
    具体的に、こちらのスクリプトは どのフォルダの中に
    何というファイル名で保存すればいいのでしょうか?
    詳しい方はすぐに分かるんだと思うんですけど。
    すみません^^;

    https://ipv4.fetus.jp/ から、国別の大量のIPをTXT形式で保存して。
    こちらのスクリプトと同じフォルダに置いておくわけですよね?

    具体的にフォルダ/ファイルの名など、tamohiko さんの
    サーバーを例として書いていただけると大変助かります^^。

    2つめは、
    最近かなり困っていることがあります。
    実は、バーチャルホストをやってみたいのですが、
    かなり時間をかけてやっているのに、ぜんぜんうまくいきません><
    tamohikoさんは、バーチャルホストはされていますでしょうか?

    わたしは、1つの物理サーバーで2つのドメインを使いたいのですが、
    私のマンションは、固定IPに対応していないネット環境なんですね、

    非固定IPだとか、無料ドメインなのか、有料ドメインなのかで
    いろいろ設定が違うようなのですが、

    BINDやらDNSやらしているのですが、もうわけがわからないです(笑)

    ご存じでしたら教えてください!

    今日の記事も最高でした!お疲れさまでした^^

    • tamohiko より:

      sushiさん

      コメントありがとうございます。
      お返事遅くなってしまいすいません。

      (1)スクリプトの使用方法

      > 具体的に、こちらのスクリプトは どのフォルダの中に
      > 何というファイル名で保存すればいいのでしょうか?

      特に決まりはないので、どこのフォルダでもどんな名前でも大丈夫です。

      > 具体的にフォルダ/ファイルの名など、tamohiko さんの
      > サーバーを例として書いていただけると大変助かります^^。

      私が作業を行った時の手順を簡単にまとめておきます。
      作業の流れ的には/rootフォルダにIPアドレスのリストをダウンロードしてきて、そこに「ipset-create.sh」という名前でスクリプトを作成して「ipset」のBLACKLISTセットに登録といった流れになります。

      ■IPアドレスリストダウンロード
      今回は「https://ipv4.fetus.jp/krfilter」のリスト使用しました。

      # cd /root
      # wget https://ipv4.fetus.jp/krfilter.1.txt

      ■スクリプト作成
      ipsetのセットは事前に作成しておいてください。
      また、LIST(IPアドレスリストのファイル名)とSET(ipsetのセット名)の部分は適宜変更お願いします。

      # vi ipset-create.sh

      ●変更が必要になるかもしれない部分

      LIST=”krfilter.1.txt”
      SET=”BLACKLIST”

      ■スクリプト実行

      # sh -x ./ipset-create.sh

      ■登録確認
      ipsetのセットに情報が登録されているか確認します。

      # ipset list BLACKLIST

      (2)バーチャルホストについて

      質問が何点かありますので教えてください。

      ・使用しているOSを教えてください

      ・使用しているWebサーバは何をお使いですか?
        apacheですか?それともnginx?

      ・ドメインについて
        非固定IP環境で運用しようとしているとのことですが、
        ドメイン自体はすでに取得されているのでしょうか?
        
        また、この環境であればDDNS環境での運用になるのかなと思うのですが、
        こちらの方の設定は完了していますか?

      このあたりの情報お教えいただければ、お力になれることはあると思いますよ。

      以上、よろしくお願いいたします。

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