●概要
※CentOS 8からTCP Wrapperは使用できなくなりました。
参考URL:hosts.allow で sshd への接続を日本国内のみに制限する
海外から自宅サーバのSSHへの不正アクセスが多く、ルータで一つ一つ拒否設定を設定していく作業が煩わしい。
このため、自宅サーバのSSHへのアクセスは原則国内限定とし、更に国内から不正アクセス検知時のみルータで拒否設定する方針に変更したいと思いました。
国内限定するにしても、そのネットワークアドレスは非常に多く、/etc/hosts.allow、/etc/hosts.denyを利用することとします。
これまで利用してきた、firewalld、denyhosts、fail2ban等はそのまま利用します。
●設定(Rocky 8、Rocky 9)
参考URL:システムエクスプレス株式会社
参考URL:ipsetで大量のBlock指定を行う
国内のIPアドレスのリストを作成します。
ipsetの再適用
現在適用されたipsetを削除するには下記のようにします。
ただし、削除するエントリーのファイル名が同じでも追加した時の内容と異なっている場合、削除しても下記のようにエントリーが残ってしまうことがあります。
Rocky 9における、インターネット側からhttp及びhttpsでアクセスできない現象への対応
CentOS Stream 8、Rocky 8では起きていなかった現象がRocky 9で発生しました。
tcpdumpで調べると(157.65.27.0/24は、今回ポート開放確認のために使用したサイト)
そこで、nftコマンドでフィルタールールを調べてみます。
いろいろ調べた結果(firewalldを停止すると接続できるようになる)、domesticゾーンによる影響でした。
イントラネットからでもアクセスできるようにpublicゾーンに設定済みの、http及びhttpsはそのまま残しておきます。
(残しておかないと、イントラでの接続が出来なくなります。)
●設定(CentOS 7)
複数のCIDRブロックを集約 (aggregation) するため、aggregateをyumでインストールします。
ローカルホストからのアクセスは許可するために、hosts.allowの先頭に次の1行を追加します。
※CentOS 8からTCP Wrapperは使用できなくなりました。
参考URL:hosts.allow で sshd への接続を日本国内のみに制限する
海外から自宅サーバのSSHへの不正アクセスが多く、ルータで一つ一つ拒否設定を設定していく作業が煩わしい。
このため、自宅サーバのSSHへのアクセスは原則国内限定とし、更に国内から不正アクセス検知時のみルータで拒否設定する方針に変更したいと思いました。
国内限定するにしても、そのネットワークアドレスは非常に多く、/etc/hosts.allow、/etc/hosts.denyを利用することとします。
これまで利用してきた、firewalld、denyhosts、fail2ban等はそのまま利用します。
●設定(Rocky 8、Rocky 9)
参考URL:システムエクスプレス株式会社
参考URL:ipsetで大量のBlock指定を行う
国内のIPアドレスのリストを作成します。
# mkdir /root/iptables
# vi /root/iptables/jpip_setup.sh
#!/bin/bash
COUNTRYLIST='JP'
curl -s -o /root/iptables/delegated-apnic-latest http://ftp.apnic.net/stats/apnic/delegated-apnic-latest
:> /root/iptables/jpip
for country in $COUNTRYLIST
do
for ip in `cat /root/iptables/delegated-apnic-latest | grep "apnic|$country|ipv4|"`
do
COUNTRY=`echo $ip | awk -F"|" '{ print $2 }'`
IPADDR=`echo $ip | awk -F"|" '{ print $4 }'`
TMPCIDR=`echo $ip | awk -F"|" '{ print $5 }'`
FLTCIDR=32
while [ $TMPCIDR -ne 1 ];
do
TMPCIDR=$((TMPCIDR/2))
FLTCIDR=$((FLTCIDR-1))
done
echo "$IPADDR/$FLTCIDR" >> /root/iptables/jpip
done
done
# chmod 700 /root/iptables/jpip_setup.sh
# /root/iptables/jpip_setup.sh
firewallを設定します。
# domestic(国内)というゾーンを作成します。 firewall-cmd --permanent --new-zone=domestic # domestic という ipset を作成して type を hash:net にします。 firewall-cmd --permanent --new-ipset=domestic --type=hash:net # 上記で作った国内のIPリストファイルをこの ipset に読み込みます。 firewall-cmd --permanent --ipset=domestic --add-entries-from-file=/root/iptables/jpip # この ipset に国内IPリストが読み込まれているか確認します。 firewall-cmd --permanent --info-ipset=domestic # 読み込まれた ipset をこのゾーンに適用します。 firewall-cmd --permanent --zone=domestic --add-source=ipset:domestic # publicゾーンからSSHサービスを削除します。 # firewall-cmd --permanent --zone=public --remove-service=ssh # domesticゾーンにSSHサービスを追加します。 # firewall-cmd --permanent --zone=domestic --add-service=ssh firewalld を reload します。 # firewall-cmd --reload以上でsshdへの接続は日本国内のみに制限されました。
ipsetの再適用
現在適用されたipsetを削除するには下記のようにします。
# firewall-cmd --permanent --ipset=domestic --remove-entries-from-file=/root/iptables/jpip
# firewall-cmd --reload
# ipset --list domestic
Name: domestic
Type: hash:net
Revision: 6
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 376
References: 0
Number of entries: 0
Members:
エントリー数が「0」であれば、(問題なく)全て削除されています。
ただし、削除するエントリーのファイル名が同じでも追加した時の内容と異なっている場合、削除しても下記のようにエントリーが残ってしまうことがあります。
# firewall-cmd --permanent --ipset=domestic --add-entries-from-file=/root/iptables/jpip_local_ip ← 故意に、ローカルネットワークが余計に追加されているセットを適用 # firewall-cmd --reload プライベートアドレスが記載されていないエントリーファイルでipsetを削除 # firewall-cmd --permanent --ipset=domestic --remove-entries-from-file=/root/iptables/jpip # firewall-cmd --reload # ipset --list domestic Name: domestic Type: hash:net Revision: 6 Header: family inet hashsize 1024 maxelem 65536 Size in memory: 568 References: 0 Number of entries: 3 Members: 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16このように新たなエントリーファイルを再適用するには注意して対応する必要があります。
Rocky 9における、インターネット側からhttp及びhttpsでアクセスできない現象への対応
CentOS Stream 8、Rocky 8では起きていなかった現象がRocky 9で発生しました。
tcpdumpで調べると(157.65.27.0/24は、今回ポート開放確認のために使用したサイト)
# tcpdump -i eno1 net 157.65.27.0 mask 255.255.255.0
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eno1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
17:39:02.885522 IP 157-65-27-7.vpscloud.static.arena.ne.jp.49354 > hostA.http: Flags [S], seq 894457425, win 29200, options [mss 1420,sackOK,TS val 232270987 ecr 0,nop,wscale 7], length 0
17:39:02.885625 IP hostA > 157-65-27-7.vpscloud.static.arena.ne.jp: ICMP host hostA unreachable - admin prohibited filter, length 68
のようになり、デフォルトでフィルターがかかっているっぽい。
そこで、nftコマンドでフィルタールールを調べてみます。
・CentOS Stream 8
# nft list ruleset | grep -n reject
214: reject with icmpx admin-prohibited
222: ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 addr-unreachable
230: reject with icmpx admin-prohibited
237: ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 addr-unreachable
・Rocky Linux 9
# nft list ruleset | grep -n reject
2350: reject with icmpx admin-prohibited
2359: ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 addr-unreachable
2361: reject with icmpx admin-prohibited
2368: ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 addr-unreachable
2415: reject with icmpx admin-prohibited
2467: reject with icmpx admin-prohibited
2544: reject with icmpx admin-prohibited
2626: reject with icmpx admin-prohibited
明らかに違いがあります。
いろいろ調べた結果(firewalldを停止すると接続できるようになる)、domesticゾーンによる影響でした。
イントラネットからでもアクセスできるようにpublicゾーンに設定済みの、http及びhttpsはそのまま残しておきます。
(残しておかないと、イントラでの接続が出来なくなります。)
# firewall-cmd --permanent --zone=domestic --add-service={http,https}
# firewall-cmd --reload
# firewall-cmd --list-all --zone=domestic
:
services: http https ssh
:
このように対応することで、インターネット側から接続できるようになりました。
●設定(CentOS 7)
複数のCIDRブロックを集約 (aggregation) するため、aggregateをyumでインストールします。
# yum install -y aggregate各ファイルを格納するためのディレクトリを作成します。
# mkdir /root/countryfilter # cd /root/countryfilter
# vi conv.pl
#!/bin/perl
use strict;
while (<STDIN>) {
chomp;
my ($registry, $cc, $type, $start, $value, undef, $status) = split(/\|/);
unless ($type eq 'ipv4' && ($status eq 'allocated' || $status eq 'assigned')) { next; }
#unless ($cc eq 'JP') { next; }
my $SubnetMaskBin = sprintf('%b', scalar($value));
if ($SubnetMaskBin !~ /^1(0+)$/) {
# CIDR 表記できない
next;
}
my $prefix = 32 - length($1);
my $num;
$num = ($num << 8) + $_ foreach (split(/\./, $start));
if (($num % $value) != 0) {
# 分割しなければならない
next;
}
print $start.'/'.$prefix."\t".$cc."\n";
}
while (<STDIN>) {
chomp;
my ($registry, $cc, $type, $start, $value, undef, $status) = split(/\|/);
unless ($type eq 'ipv4' && ($status eq 'allocated' || $status eq 'assigned')) { next; }
#unless ($cc eq 'JP') { next; }
my $SubnetMaskBin = sprintf('%b', scalar($value));
if ($SubnetMaskBin !~ /^1(0+)$/) {
# CIDR 表記できない
next;
}
my $prefix = 32 - length($1);
my $num;
$num = ($num << 8) + $_ foreach (split(/\./, $start));
if (($num % $value) != 0) {
# 分割しなければならない
next;
}
print $start.'/'.$prefix."\t".$cc."\n";
}
日本国内のIPアドレスリスト(ip.txt)を生成してhosts.allowに書き込むシェルスクリプト(update.sh)を作成します。
# vi update.sh
R=$(cd $(dirname $0); pwd)
cd $DIR
# aggregate がインストールされているかチェック
aggregate=`which aggregate 2> /dev/null | wc -l`
if [ $aggregate -ne 1 ]; then
echo "aggregate: command not found" >&2
exit 1
fi
# 各 RIP から IP アドレスの割当リストを取得
rm -f ./delegated-*
wget ftp://ftp.arin.net/pub/stats/arin/delegated-arin-latest > /dev/null 2>&1
wget ftp://ftp.ripe.net/pub/stats/ripencc/delegated-ripencc-latest > /dev/null 2>&1
wget ftp://ftp.apnic.net/pub/stats/apnic/delegated-apnic-latest > /dev/null 2>&1
wget ftp://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-latest > /dev/null 2>&1
wget ftp://ftp.afrinic.net/pub/stats/afrinic/delegated-afrinic-latest > /dev/null 2>&1
if [ ! -f delegated-apnic-latest ]; then
echo "delegated-apnic-latest was not found." >&2
exit 1
fi
# 日本国内のもののみを取り出して集約
cat delegated-* | perl ./countryfilter/conv.pl | grep -E 'JP$' | sort -n | aggregate -q > jp.txt
# CIDR 表記をサブネットマスク表記に変換
sed -i 's/\/8$/\/255.0.0.0 /' ./jp.txt
sed -i 's/\/9$/\/255.128.0.0 /' ./jp.txt
sed -i 's/\/10$/\/255.192.0.0 /' ./jp.txt
sed -i 's/\/11$/\/255.224.0.0 /' ./jp.txt
sed -i 's/\/12$/\/255.240.0.0 /' ./jp.txt
sed -i 's/\/13$/\/255.248.0.0 /' ./jp.txt
sed -i 's/\/14$/\/255.252.0.0 /' ./jp.txt
sed -i 's/\/15$/\/255.254.0.0 /' ./jp.txt
sed -i 's/\/16$/\/255.255.0.0 /' ./jp.txt
sed -i 's/\/17$/\/255.255.128.0 /' ./jp.txt
sed -i 's/\/18$/\/255.255.192.0 /' ./jp.txt
sed -i 's/\/19$/\/255.255.224.0 /' ./jp.txt
sed -i 's/\/20$/\/255.255.240.0 /' ./jp.txt
sed -i 's/\/21$/\/255.255.248.0 /' ./jp.txt
sed -i 's/\/22$/\/255.255.252.0 /' ./jp.txt
sed -i 's/\/23$/\/255.255.254.0 /' ./jp.txt
sed -i 's/\/24$/\/255.255.255.0 /' ./jp.txt
sed -i 's/\/25$/\/255.255.255.128 /' ./jp.txt
sed -i 's/\/26$/\/255.255.255.192 /' ./jp.txt
sed -i 's/\/27$/\/255.255.255.224 /' ./jp.txt
sed -i 's/\/28$/\/255.255.255.240 /' ./jp.txt
# /etc/hosts.allow をバックアップ
NOW_TIME=`date +%Y%m%d_%H%M%S`
cp -p /etc/hosts.allow /etc/hosts.allow_bk${NOW_TIME}
# /etc/hosts.allow をリセット
sed -i -e '/#countryfilter/d' /etc/hosts.allow
# 日本国内の IP アドレスリストを書込
cat ./jp.txt | awk '{print "sshd: "$1" #countryfilter"}' >> /etc/hosts.allow
hosts.denyを編集して、sshdへのアクセスを原則禁止とします。
# vi /etc/hosts.deny sshd: ALL※ sshで作業している場合、この時点で切断すると再接続できなくなるので注意してください。
ローカルホストからのアクセスは許可するために、hosts.allowの先頭に次の1行を追加します。
# vi /etc/hosts.allow ALL: 127.0.0.1, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, (その他のNWアドレス等) :作成したシェルスクリプトに実行権を与えて、実行します。
# chmod 700 update.sh # ./update.shcronで一週間ごとに実行するように設定します。
# ln -s /root/countryfilter/update.sh /etc/cron.weekly/以上でsshdへの接続は日本国内のみに制限されました。