【VPS・Linuxサーバー入門】ip6tablesからのWebARENA IndigoのVPSへIPv6仕様のファイアウォールを設定する


2022/12/15
【VPS・Linuxサーバー入門】iptablesからクライアントのMACアドレスごとにConoHa VPSのファイアウォールを設定する
蛸壺の技術ブログ|ip6tablesからのWebARENA IndigoのVPSへIPv6仕様のファイアウォールを設定する

以前の記事で
「WebARENA Indigo」でもっともミニマム(768MB/1vCPU/20GB/100Mbps)でその分格安なLinuxインスタンスを立ち上げて使ってみる内容を紹介しました。

合同会社タコスキングダム|蛸壺の技術ブログ
【VPS・Linuxサーバー入門】WebARENA IndigoのVPSでお手頃な値段でプライベートLinuxサーバーを試そう

『WebARENA Indigo』のVPSサービスを使って、料金を控えめに始められるLinuxサーバーを扱う手順を紹介していきます。

このインスタンスは格安で使える代償として、
「IPv6でしか使えない」という制約が存在します。

ということで、いまだ主流のIPv4ではこのVPSインスタンスを上手く扱うことができません。

これはファイアウォールの構築を考えるのにも影響があり、IPv4をベースにファイアウォールを記述する
iptablesは利用することが出来ません。

通常の
iptablesに代わり、IPv6のファイアウォールを構築するためのツールが「ip6tables」です。

今回は、WebARENA IndigoのLinuxインスタンスにip6tablesで簡単なファイアウォールを作成する手順を考えてみましょう。


合同会社タコスキングダム|蛸壺の技術ブログ

WebARENA IndigoのDebianインスタンスにユーザーを追加する

作りたてのDebianインスタンスには、debainという名前でデフォルトユーザーが追加されています。

ただし、このデフォルトユーザーは最初からsudoできるように管理者権限を持っていますが、
パスワードがありません

このままだと無防備ですので、
debianという名前を別の名前に変更し、パスワードを付与しましょう。

デフォルトユーザーだけだと、自分で自分の情報を書き換えできないため、一時的に作業用ユーザー・
tmpを追加します。

まずは
前回の要領debianでSSHログイン後、下記のコマンドでrootに昇格させて、作業を試みます。

            
            $ whoami
debian

#👇rootユーザーに切り替え
$ sudo su -
~# whoami
root
        
ではrootから、以下のようにtmpユーザーを新規追加しましょう。

            
            #👇作業ユーザーの追加
~# useradd -m tmp

#👇作業ユーザーにsudoを行う権限グループに追加
~# gpasswd -a tmp sudo

#👇作業ユーザーのパスワードを追加
~# passwd tmp

#👇SSH公開鍵をdebianのものから借用
~# mkdir /home/tmp/.ssh
~# cp /home/debian/.ssh/authorized_keys /home/tmp/.ssh/
~# chown -R tmp:tmp /home/tmp/.ssh
        
作業用ユーザーが追加できたので、一旦SSH接続をログアウトして、今度はSSHクライアント側の~/.ssh/configを以下のように修正して、作業用ユーザー・tmpでSSHログインし直します。

            
            Host tmp
  HostName 2001:********
  User tmp
  Port 22
  IdentityFile "~/.ssh/private-key"
        
SSHでtmpで入り直したら、再びrootからデフォルトユーザー・debianを再設定していきます。

            
            $ ssh tmp
Linux i-1*********6 5.10.0-16-amd64 #1 SMP Debian 5.10.127-1 (2022-06-30) x86_64
#...

$ whoami
tmp

$ sudo su -
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.
[sudo] password for tmp: 

#👇rootにログイン
~# whoami
root
        
ここでは一例として、debianからhogeに名前・ホームディレクトリ・グループを変更しましょう。

            
            ~# usermod -l hoge debian
~# usermod -d /home/hoge -m hoge
~# groupmod -n hoge debian
        
もともとdebianにはパスワードが設定されていないので、パスワードも新たに追加します。

            
            ~# passwd hoge
New password: 
Retype new password: 
passwd: password updated successfully
        
設定したパスワードは忘れずに控えておきましょう。

デフォルトユーザーの設定を変更したら、
tmpは用済みですので、SSHログアウトして、デフォルトユーザー・hogeで入り直します(※SSH接続にはクライアント名がdebainからhogeになるのに注意)。

            
            $ ssh hoge
Linux i-1*********6 5.10.0-16-amd64 #1 SMP Debian 5.10.127-1 (2022-06-30) x86_64
#...

$ whoami
hoge
        
問題なくデフォルトユーザーがhogeに置き換わりました。

最後に用済みの
tmpのユーザー削除を行います。

            
            $ sudo userdel tmp
$ sudo rm -rf /home/tmp
        
なお、SSHのデフォルトのポート番号もできれば変更することをおすすめします。

変更の手順は前の回で説明していたのでここではその内容は省略します。


合同会社タコスキングダム|蛸壺の技術ブログ

ip6tablesでファイアウォールの構築する

デフォルトユーザーも設定し終えたので、ここから早速IPv6ベースのファイアウォールを「ip6tables」で設定していきます。

ちなみに、IPv6の仕組みはIPv4と比べると格段に複雑で、アドレス値も128bitになるため、一目では理解しにくくなっています。

IPv6の詳細に関しては、以下のサイトでネットワークエンジニアの方が簡潔に説明されていますので、そちらでお勉強されてください。

参考サイト|IPv6アドレスとは、表記/省略方法、EUI-64、DHCPv6、ICMPv6、Tunneling

iptables-persistentでファイアウォールを管理

前回の「ConoHa VPS」のファイアウォール設定編で説明した「iptables-persistent」はIPv6でのファイアウォール構築にも便利です。なので、ここでも導入しておきます。

            
            $ sudo apt update
$ sudo apt upgrade -y
$ sudo apt install iptables-persistent -y
        

標準的なファイアウォールを構築する

何をもって標準とするかはVPSでやりたい目的で異なるとは思いますが、ここでは例としてArchLinuxのファイアウォールの構築例として取り上げられている・シンプルなステートフルファイアウォール

を参考にファイアウォールを作成していきます。

WebARENA VPSのインスタンスの持っているネットワークインターフェースを一度把握してみます。

            
            $ ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:11:22:33:44:55 brd ff:ff:ff:ff:ff:ff
    altname enp0s10
    inet6 2001:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::xxxx:xxxx:xxxx:xxxx/64 scope link 
       valid_lft forever preferred_lft forever
        
存在しているインターフェースはループバックを除くと、イーサネットインターフェース(ここではens10)が1つだけのようです。

このインターフェースで、
2001:...から始まるものが、『グローバルユニキャストアドレス』であり、IPv6インターネット用アドレスとして利用されています。

もう一つの
fe80::...が、『リンクローカルアドレス』でローカルネットワークの同一セグメント内で有効なプライベートアドレスです。

現在のファイアウォールを眺めてみましょう。

            
            $ sudo ip6tables -vnL --line-number
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination
        
当然ながら何もルールが存在していませんので、まっさらな状態からファイアウォールを設定していきます。

もし既存のファイアウォールが存在している場合、一旦まっさらにリセットしておきましょう。

            
            $ sudo netfilter-persistent flush
        
最初にループバックからの自分自身への接続と、TCP通信で既に確立した接続の通信は基本的に許可します。

            
            $ sudo ip6tables -A INPUT -i lo -j ACCEPT
$ sudo ip6tables -A INPUT -i ens10 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
        
ちなみに-iオプションには存在しているインターフェース名を利用しますので、適宜ご自分の環境に合わせてデバイス名を置き換えてください。

また接続が無効となったパケットは破棄させておきましょう。

            
            $ sudo ip6tables -A INPUT -m conntrack --ctstate INVALID -j DROP
        

ICMPv6周りの設定

ICMPv6(Internet Control Message Protocol for IPv6)は、IPv6で使用されるICMPプロトコルのことで、IPv6においてエラー通知やpingやMACアドレス解決等でこのICMPv6が重要な役割をもっています。

ICMPv6にはメッセージタイプが0~255の番号で存在しており、中でも重要なタイプのメッセージが以下のように存在しています。

タイプ

メッセージ内容

分類

1

Destination Unreachable (宛先到達不能)

エラー

2

Packet too Big (パケット過大)

エラー

3

Time Exceeded (時間切れ)

エラー

4

Parameter Problem (パラメータ異常)

エラー

128

Echo Request (エコー要求)

情報

129

Echo Reply (エコー応答)

情報

130

Multicast Listener Query

情報

131

Multicast Listener Report

情報

132

Multicast Listener Done

情報

133

Router Solicitation (ルーター要請)

近隣探索

134

Router Advertisement (ルーター広告)

近隣探索

135

Neighbor Solicitation (近隣要請)

近隣探索

136

Neighbor Advertisement (近隣広告)

近隣探索

137

Redirect

近隣探索

このメッセージタイプを個別に通過させる・させないを細かく制御することで、よりセキュリティの強化されたファイアウォールが構築できるようになります。

例えばセキュリティ的には甘くなりますが、不特定者からのPING(エコー要求:128)受信を許可したい場合には以下を追加します。

            
            $ sudo ip6tables -A INPUT -p ipv6-icmp \
    -m icmp6 --icmpv6-type 128 \
    -m conntrack --ctstate NEW \
    -j ACCEPT
        
VPSでリモート間アクセスするのにもっとも関連のあるのが、NS(Neighbor Solicitation)の135とNA(Neighbor Advertisement)の136です。

これら2つを許可しておかないと、ネットワーク内の他のインターフェースのリンク層アドレス(MACアドレス)情報を交換することができなくなります。

グローバルからの
NS(ICMPv6の135)NA(ICMPv6の136)の受信は必ず許可しておきましょう。

            
            $ sudo ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 135 -j ACCEPT
$ sudo ip6tables -A INPUT -p ipv6-icmp -m icmp6 --icmpv6-type 136 -j ACCEPT
        
これで最低限の接続がIPv6で可能になります。

なおこの設定だと全てパケットを通過させてしまう意味で、以下のルールの略記形式になっています。

            
            $ sudo ip6tables -A INPUT -s ::/0 -d ::/0 -p ipv6-icmp \
    -m icmp6 --icmpv6-type 135 -j ACCEPT
$ sudo ip6tables -A INPUT -s ::/0 -d ::/0 -p ipv6-icmp \
    -m icmp6 --icmpv6-type 136 -j ACCEPT
        
送信元(-s)も送信先(-d)もだれでも(::/0)制限なく通過させてしまうのが好ましくないなら、以下のような要領で個別のIPやアドレスグループに送信元・送信先を指定も可能です。

            
            #👇リンクローカルアドレスを許可
$ sudo ip6tables -A INPUT -s fe80::/64 -d fe80::/64 -p ipv6-icmp -m icmp6 --icmpv6-type 135 -j ACCEPT
$ sudo ip6tables -A INPUT -s fe80::/64 -d fe80::/64 -p ipv6-icmp -m icmp6 --icmpv6-type 136 -j ACCEPT

#👇ユニークローカルアドレスを許可
$ sudo ip6tables -A INPUT -s fd00::/64 -d fe80::/64 -p ipv6-icmp -m icmp6 --icmpv6-type 135 -j ACCEPT
$ sudo ip6tables -A INPUT -s fd00::/64 -d fe80::/64 -p ipv6-icmp -m icmp6 --icmpv6-type 136 -j ACCEPT

#👇グローバルユニキャストを許可
$ sudo ip6tables -A INPUT -s 2001:xxxx:xxxx:xxxx::/64 -d 2001:xxxx:xxxx:xxxx::/64 -p ipv6-icmp -m icmp6 --icmpv6-type 135 -j ACCEPT
$ sudo ip6tables -A INPUT -s 2001:xxxx:xxxx:xxxx::/64 -d 2001:xxxx:xxxx:xxxx::/64 -p ipv6-icmp -m icmp6 --icmpv6-type 136 -j ACCEPT
        
というような感じに使います。

プロトコルごとにユーザー定義チェーンでまとめる

プロトコル別にポートを拡張しやすいように、TCPUDPの2つのユーザー定義チェインを新規作成しましょう。

            
            $ sudo ip6tables -N TCP
$ sudo ip6tables -N UDP
        
ユーザー定義チェーンは、INPUTチェーンから分岐させる形で該当のプロトコルを検出したら各定義チェーンにジャンプさせるように仕向けます。

            
            $ sudo ip6tables -A INPUT -p tcp --syn \
    -m conntrack --ctstate NEW -j TCP
$ sudo ip6tables -A INPUT -p udp \
    -m conntrack --ctstate NEW -j UDP
        
TCP系のサービスはTCPチェーンにまとめてルールを仕込みます。

例えばここでは、SSH(デフォルトポート22)のリモート接続を許可するために、先程の節で22番から変更したポート番号で新規に確立したSSH通信だけを許可するルールを追加します。

            
            $ sudo ip6tables -A TCP -p tcp -m state --syn \
    --state NEW --dport <許可したいポート番号> -j ACCEPT
        
ここでは紹介しませんが、TCPで他に良く使われるのが、WEBサーバーのHTTP(デフォルトポート80)やHTTPS(デフォルトポート443)などあります。

ここらへんはご自身の目的に応じてTCPルールに追加してみてください。

UDPチェーンも紹介した手前、何も追加しないのもアレなので、ぱっと思いつくものはUDP系で利用しそうなサービスに独自のDHCPサーバーがあります。

DHCPサーバーはVPSインスタンスで利用することはまずなさそうですが、自宅でDHCPサーバーなどを立てる際には、DHCPv6でやり取りするときに使われるウェルノウンポート・546番からのパケットを受信する必要があります。

個人的な経験上、いざDHCPサーバーを構築するときに、「なんでDHCPが有効にならないのだろう...」と色々と悩んで、後々ファイアウォールで弾いていたというオチもあるので、
UDPチェーンにDHCPv6関連ポートからの受信を許可しておきます。

            
            $ sudo ip6tables -A UDP -s fe80::/64 -p udp --dport 546 \
    -m conntrack --ctstate NEW -j ACCEPT
        

UDPはTCPと比較してマイナーな利用法が多いかもしれませんが、WebRTC用にSTUN/TURNサーバーのポート番号でフォルトは3478などもこのUDPチェーンに登録できるかもしれません。

            
            $ sudo ip6tables -A UDP -p udp --dport 3478 \
    -m conntrack --ctstate NEW -j ACCEPT
        
ここらへんは臨機応変にルールを追加してみてください。

不明なパケットをREJECTさせる

REJECTターゲットはDROPターゲットと違って、棄却する際にエラーを返します。

開発中サービスでサーバー側から弾かれた理由が知りたいときには便利ですが、攻撃者にも何かしら攻撃のヒントを与えてしまうかもしれませんので、いらなければ設定しないほうが良いかもしれません。

            
            #👇TCPターゲット、UDPターゲット以外の場合にエラーパケットを送信&パケット破棄
$ sudo ip6tables -A INPUT -p tcp -j REJECT --reject-with tcp-reset
$ sudo ip6tables -A INPUT -p udp -j REJECT --reject-with icmp6-adm-prohibited
#👇それ以外の不定なプロトコルでエラーパケットを送信&パケット破棄
$ sudo ip6tables -A INPUT -j REJECT --reject-with icmp6-adm-prohibited
        

デフォルトポリシーの書き換え

最後にINPUT・FORWARD・OUTPUTチェーンの基本ポリシーを設定します。

            
            $ sudo ip6tables -P FORWARD DROP
$ sudo ip6tables -P OUTPUT ACCEPT
$ sudo ip6tables -P INPUT DROP
        
SSH接続でリモートVPSインスタンスに接続する場合、INPUTターゲットの設定に不備があると、-P INPUT DROPした直後に、SSHが音信不通になるかもしれません。

もしこのような症状が起こった場合、焦らずに次の項目で解説する内容をよく読んで対処してみてください。

ファイアウォールが正常に設定できたなら、忘れずに現在の設定を以下のコマンドで永続化しておきましょう。

            
            $ sudo netfilter-persistent save
        
以上でWebARENA IndigoのインスタンスでもIpv6ベースのファイアウォールが設定することが可能になりました。

ファイアウォール設定中にSSH繋がらなくなったときの対処法

フィルターの設定内容・フィルターの設定順序を間違えるとSSH接続できなくなるときがあります。

もしもまだ
netfilter-persistent saveで正常なファイアウォールの「復元ポイント」に戻れる場合には、WebARENA Indigoのインスタンスの再起動を行ってください。

有効な復元ポイントがなかったり、誤って無効なファイアウォールで復元ポイントを作成してしまい後戻りが効かない場合には、WebARENA Indigoのダッシュボードから、
[インスタンス管理] > [インスタンス] > 問題のあるインスタンスを選択 > [コンソールを起動]して、ブラウザからリカバリーモードでアクセスしてみてください。

ユーザーでログイン出来たらなら、
sudo netfilter-persistent flushすると、問題のあるファイアウォールごとリセットすることが可能です。

合同会社タコスキングダム|蛸壺の技術ブログ


合同会社タコスキングダム|蛸壺の技術ブログ

まとめ

今回は、通常のIPv4ベースのiptablesで構築するファイアウォールとは少しことなる視点から、IPv6標準のファイアウォールをip6tablesで構築する方法を簡単に解説してみました。

特にip6tablesの使い方は、ほぼiptablesと変わらないのですが、これを使いこなすにはIPv6の規格をよく理解しておく必要があります。

まずはIPv6のファイアウォールを構築しようとする前に、十分IPv6の仕組みを学習した上で設定してみてください。