nftablesでSSHを日本国内からの接続に限定する (CentOS 8)

isdはじめに

以前、国別のIPアドレスリストを利用して、CentOS 7で、ipset と iptables で SSH を日本国内からの接続に限定する設定方法をまとめました。

・ipsetとiptablesでSSHを日本国内からの接続に限定する (CentOS 7)
https://inaba-serverdesign.jp/blog/20150209/ipset_iptables_country_centos7.html

今回は、CentOS 8 で同じことを実現します。
CentOS 8 では、パケットフィルタ―機能のバックエンドが、iptables から nftables に変更となりました。
引き続きフロントエンドとして iptables や firewalld も使用できますが、どちらを使用してもバックエンドは nftables となります。

CentOS 8 でも、ipset + iptables, ipset + firewalld を使用して日本国内のIPアドレスのみのアクセス制限が実現できますが、nftables は、パケットフィルタ―の処理やルールの追加・削除処理の性能がよいとのことで、ここでは、フロントエンドも nftables を使用します。
また、ipset と nftables を組み合わせて使用することはできないため、nftables のみで設定します。

ここでまとめた設定方法は、AWS EC2の FrontLineが提供する CentOS 8 AMI を使用して動作確認済みです。

なお、ここでは、nftablesそのものについての詳しい説明は省略します。
参考記事を参照してください。

isd設定のポイント

以前のCentOS 7での設定では、日本の大量のIPアドレスリストを、iptable のルールに含めるのではなく、ipset で管理しました。

nftables での実現方法としては、以下の情報がありました。

・nftables ip set multiple tables – StackExchange, UNIX & Linux
https://unix.stackexchange.com/questions/329971/nftables-ip-set-multiple-tables

IPアドレスリストを外部ファイルでまとめて、nftalbes.conf でその外部ファイルを include すればよいとのことです。
この情報では、ブラックリストを作成していますが、今回は「日本国内からのみ許可する」ため、ホワイトリストを作成します。

isdnftablesの設定

日本のIPアドレスリストファイルを作成

国別のIPアドレスリストは、今回も「世界の国別 IPv4 アドレス割り当てリスト」を使用させていただきます。
ありがとうございます。

 # vim /root/bin/mk_country_whitelist.sh

#!/bin/bash
#
WORKDIR=/root/bin
WHITELISTSET_FILE=/etc/nftables/country_whitelist
WHITELIST_COUNTRY='JP'

cd ${WORKDIR}/
if [ -s cidr.txt ]; then
    mv cidr.txt cidr.txt.bak
fi

wget http://nami.jp/ipv4bycc/cidr.txt.gz
gunzip cidr.txt.gz

echo "define country_whitelist = {" > ${WHITELISTSET_FILE}

for COUNTRY in ${WHITELIST_COUNTRY}
do
    sed -n "s/^${COUNTRY}\t//p" cidr.txt | while read ADDRESS
    do
        echo "  ${ADDRESS}," >> ${WHITELISTSET_FILE}
    done
done

echo "}" >> ${WHITELISTSET_FILE}

# EOF

 

実行権限を付与して実行します。

 # chmod 700 /root/bin/mk_country_whitelist.sh
 # /root/bin/mk_country_whitelist.sh

 

作成したIPアドレスのリストファイルを確認します。

 # less /etc/nftables/country_whitelist

define country_whitelist = {
  1.0.16.0/20,
  1.0.64.0/18,
  1.1.64.0/18
...
  223.252.64.0/19,
  223.252.112.0/20,
}

 

↑IPアドレス範囲が、カンマ区切りで記載されていればOKです。
このスクリプトでは、IPアドレス範囲の最後の行の末尾にもカンマが付与されてしまいますが、nftables が include するときに削除してくれるので、問題ありません。

nftables のConfig

Webサーバーを想定して、以下のシンプルなルールとします。

  • Outbound通信はすべて許可。
  • Forward通信はすべて破棄。
  • Inbound通信はデフォルト破棄で、特定のパケットのみ許可。
  • ローカルループバックインタフェース(lo)からのアクセスをすべて許可。
  • HTTP(TCP/80), HTTPS(TCP/443)へのアクセスはすべて許可。
  • ICMPは、Echo Reply(ping応答), Destination Unreachable, Time Exceeded のみ許可。
  • SSH(TCP/22)へのアクセスは、日本国内のIPアドレスからのみ許可。

nftablesのルールを、/etc/nftables/nftables.conf に記述します。
これは、CentOS 8 systemd の nftables サービスのユニットファイル内で、nftables の起動時に /etc/sysconfig/nftables.conf のルールセットを適用するよう定義されているためです。

 # view /usr/lib/systemd/system/nftables.service

...
ExecStart=/sbin/nft -f /etc/sysconfig/nftables.conf
ExecReload=/sbin/nft 'flush ruleset; include "/etc/sysconfig/nftables.conf";'
ExecStop=/sbin/nft flush ruleset
...

 

 # vim /etc/nftables/nftables.conf

flush ruleset

include "/etc/nftables/country_whitelist"

table ip filter {
  set country_accept {
    type ipv4_addr; flags interval;
    elements = $country_whitelist
  }

  chain INPUT {
    type filter hook input priority 0; policy drop;

    iifname "lo" counter accept

    ct state established,related counter accept

    ct state new tcp dport 80 counter accept
    ct state new tcp dport 443 counter accept
    ct state new tcp dport 22 ip saddr @country_accept counter accept

    icmp type echo-reply counter accept
    icmp type destination-unreachable counter accept
    icmp type time-exceeded counter accept
  }

  chain FORWARD {
    type filter hook forward priority 0; policy drop;
  }

  chain OUTPUT {
    type filter hook output priority 0; policy accept;
  }
}

# EOF

 

ルールの一部について補足します。

flush ruleset

↑既存のnftablesルールセットをすべて削除します。
不要かもしれませんが、初回設定時などに、既存ルールセットにこのConfigの設定を追加してしまうことで、正しい動作確認ができなくなる可能性もあるので、既存のルールセットを削除することでそれを防ぎます。
 

include "/etc/nftables/country_whitelist"

↑日本のIPアドレスリストファイルを Include します。
 

  set country_accept {
    type ipv4_addr; flags interval;
    elements = $country_whitelist
  }

↑名前付きセット country_accept を作成し、その値(のリスト)は、日本のIPアドレスリストファイルで定義(define)した country_whitelist とします。
 

    ct state new tcp dport 22 ip saddr @country_accept counter accept

↑SSH(TCP/22)ポート宛てのアクセス元IPアドレスは、名前付きセット country_accept を参照します。
 

    icmp type echo-reply counter accept
    icmp type destination-unreachable counter accept
    icmp type time-exceeded counter accept

↑ICMPは、Echo Reply(ping応答), Destination Unreachable, Time Exceeded のみ許可します。
必要に応じて、Echo Request (ping) などの許可するとよいでしょう。
Destination Unreachable と Time Exceeded を許可するのは、15年ぐらい前にルータの設定を行ったときに、これらを許可しなかったことが原因で、「特定のクライアントからWebサーバーにアクセスできない」という不具合が発生したからです。
今はこのような設定は不要かもしれませんが、僕は念のため設定するようにしています。

firewalldを停止

firewalld が起動している場合は、停止し、自動起動を無効にします。

 # systemctl stop firewalld

 # systemctl disable firewalld

 # systemctl status firewalld

● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor >
   Active: inactive (dead)
     Docs: man:firewalld(1)

 

(参考)設定ミスへの備え

ここで nftables を起動すると、今回の設定が反映されます。
しかし、何らかの設定ミスがあると、SSH接続ができなくなる可能性もあります。

コンソールやAWSの Session Manager のようなリモートシェル機能が使えれば、そこで nftables を停止(stop)すれば復旧できますが、それができないと、サーバーへの管理アクセス手段が失われてしまいます。

稼働中のサーバーに対して iptables, firewalld, nftables の設定を変更するのは何度やっても怖いです。
ですので僕は、稼働中のサーバーに対して iptables, firewalld, nftables を設定する際は、at コマンドを使用して、数分後にこれらのファイアウォールサービスを停止、もしくはルールを削除するよう保険をかけます。

例えば、5分後に nftables 全ルールセットを削除するコマンドはこんな感じ。

 # echo "nft flush ruleset" | at now + 5min

warning: commands will be executed using /bin/sh
job 3 at Thu Dec 19 15:05:00 2019

 

必要な設定を行って反映して、問題なければ、すぐに設定した at コマンドを削除します。

 # at -l

3       Thu Dec 19 15:05:00 2019 a root

 # atrm 3

 # at -l

 

nftablesを起動

nftables を起動し、今回の nftables ルールセットを反映します。
また、自動起動を有効にします。

 # systemctl start nftables

 # systemctl enable nftables

 # systemctl status nftables

● nftables.service - Netfilter Tables
   Loaded: loaded (/usr/lib/systemd/system/nftables.service; enabled; vendor pr>
   Active: active (exited) since Thu 2019-12-19 14:28:41 JST; 1min 28s ago
     Docs: man:nft(8)
 Main PID: 2498 (code=exited, status=0/SUCCESS)
    Tasks: 0 (limit: 5085)
   Memory: 0B
   CGroup: /system.slice/nftables.service

12月 19 14:28:41 centos8-test systemd[1]: Starting Netfilter Tables...
12月 19 14:28:41 centos8-test systemd[1]: Started Netfilter Tables.

 

すでに nftables を起動済みの場合は、再起動します。

 # systemctl restart nftables

 

nftablesルールセットを確認

nft コマンドで、カレントの nftables ルールセットを確認します。

 # nft list ruleset

table ip filter {
        set country_accept {
                type ipv4_addr
                flags interval
                elements = { 1.0.16.0/20, 1.0.64.0/18,
                             1.1.64.0/18, 1.5.0.0/16,
...
                             223.223.224.0/19, 223.252.64.0/19,
                             223.252.112.0/20 }
        }

        chain INPUT {
                type filter hook input priority 0; policy drop;
                iifname "lo" counter packets 0 bytes 0 accept
                ct state established,related counter packets 212 bytes 18628 accept
                ct state new tcp dport http counter packets 0 bytes 0 accept
                ct state new tcp dport https counter packets 0 bytes 0 accept
                ct state new tcp dport ssh ip saddr @country_accept counter packets 0 bytes 0 accept
                icmp type echo-reply counter packets 0 bytes 0 accept
                icmp type destination-unreachable counter packets 0 bytes 0 accept
                icmp type time-exceeded counter packets 0 bytes 0 accept
        }

        chain FORWARD {
                type filter hook forward priority 0; policy drop;
        }

        chain OUTPUT {
                type filter hook output priority 0; policy accept;
        }
}

 

日本のIPアドレスリストファイル /etc/nftables/country_whitelist の内容が、
elements = { … }
のところに挿入されたことがわかります。

結果的にルールセットの行数が増えてしまうので、
「パケットフィルタ―処理が遅くならないだろうか?」
という不安も出てきますが、nftables はその実装のしくみから、名前付きセット内のIPアドレスエントリーが増えても、パケットフィルタ―処理速度が大きく劣化することはない、、、はずです。

※この辺の性能面は、いつかベンチマークテストを行ってみたいと思います。

(2019.12.25追記)
ベンチマークテストで、パケットフィルタ―なし、ipset+iptables と比較し、この設定方法で名前付きセット内のIPアドレスエントリーが増えても、性能がほぼ違わないことを確認しました。

・日本国内からの接続に限定する場合のipset+iptablesとnftablesの性能比較
https://inaba-serverdesign.jp/blog/20191225/compare-ipset-iptables-nftables.html

isd動作確認

以下を確認します。

  • 自分のPCや日本国内の踏み台サーバーからSSHログインできる。
  • 海外のサーバー環境からSSHログインできない。
  • HTTP, HTTPSの受信やサーバーからインターネットへのアクセスなど、設定したSSH以外のルールが正しい。

また、可能であれば、OSを再起動して nftables ルールが正しくロードされることも確認するとよいでしょう。

「海外のサーバー環境」は、例えばAWS EC2のサーバーを使うとよいと思います。
なお、EC2サーバーのIPアドレスは、東京リージョンのサーバーでも国名コードとしては ‘US’ です。
(最近は ‘JP’ の場合もあるかもしれませんが。)
つまり、この国名コードは、必ずしも該当のIPアドレスを使用するサーバーの地理的な位置を表すとは限らないことに注意しましょう。

「海外のサーバー環境」を用意するのが難しければ、一時的に、日本のIPアドレスリストの中から、自分がアクセス元となるIPアドレス範囲を削除してテストするとよいでしょう。

isdまとめ

CentOS 8 で、nftables を使用して SSH を日本国内からの接続に限定する設定方法をまとめました。
同様の方法で、IPアドレスのブラックリストを用意して、特定の国からの接続を拒否する設定も可能です。

IaaSクラウドのサーバーで、ポート制限のみであれば、AWSのセキュリティグループのようなファイアウォール機能で十分かと思います。
しかし、iptables, firewalld や nftables を使うと、ホワイトリスト、ブラックリストで送信元、送信先IPアドレスを制限するなど、より細かい制御、セキュリティ強化が可能です。

アクセス元を日本国内のIPアドレスに限定すると、海外からの不正アクセスを大きく削減できます。
しかし、日本国内の悪意を持った第三者や、ボット感染したサーバーからの不正アクセスの可能性もありますので、「これで100%安全」というわけではないことに十分注意する必要があります。

isd参考記事

nftalbesの概要や設定については、以下の記事を参考にしました。
ありがとうございました。

・Linuxにおける新たなパケットフィルタリングツール「nftables」入門 – さくらのナレッジ
https://knowledge.sakura.ad.jp/22636/

・Red Hat Enterprise Linux 8 新機能をわかりやすく解説【RHEL8】 – Hacker’s High
https://hackers-high.com/linux/rhel8-new-features/

・iptablesの後に来るものは何か?: nftables – 赤帽エンジニアブログ
https://rheb.hatenablog.com/entry/nftables

・nftables ip set multiple tables – StackExchange, UNIX & Linux
https://unix.stackexchange.com/questions/329971/nftables-ip-set-multiple-tables

・とりあえずnftablesを動かしてみた – Qiita
https://qiita.com/huran0209/items/28bf6875bd770e291191

・iptables から nftables への移行 – 続くといいな日記
https://mizunashi-mana.github.io/blog/posts/2019/09/nftables-on-debian/
 

(関連記事)
・日本国内からの接続に限定する場合のipset+iptablesとnftablesの性能比較
https://inaba-serverdesign.jp/blog/20191225/compare-ipset-iptables-nftables.html

・ipsetとiptablesでSSHを日本国内からの接続に限定する (CentOS 7)
https://inaba-serverdesign.jp/blog/20150209/ipset_iptables_country_centos7.html

・CentOS 8のWebサーバー構築に関わる変更点
https://inaba-serverdesign.jp/blog/20191226/centos8.html
 

Follow me!