6rdプロトコルを使って、IPv6ネットワークとAmazon VPC(EC2)をつないでみた

タイトルの通りですが、IPv6を使っている自ネットワーク環境下から、Amazon VPCにVPN接続し、VPC内のインスタンスとIPv6ネットワーク配下のサーバとを通信(連携)できるようにしてみたログです。

IPv6を使う上での前提条件/要件

まず、今回話をする上での前提となる話ですが、IPv6を使っている自ネットワークの環境は以下のような状態でした。

  • 自ネットワーク内のサーバは、割り振られているIPアドレスがIPv6アドレスonlyのケースと、IPv4/IPv6のデュアルスタックとなっているケースがある。
    • どちらのパターンのサーバであっても、VPC内のインスタンスと通信したい。
  • IPv6のアドレスはGUA(Global Unicast Address: つまりグローバルなアドレス)を割り当てている。
    • 通信するサーバ(VPC内のサーバ)ã‚‚IPv6のGUAを使った宛先にしたい。


と、こんな感じでございます。

Amazon VPCではインターナルでIPv6のアドレスを割り当てられない

が、AWS公式のFAQにも記載があるとおり、現時点でAmazon VPC内では、インターナルでIPv6のアドレスが割り当てられない仕様があります。

Q: VPC 内では、どのような IP アドレス範囲を使用できますか?
RFC 1918 で定義されたプライベート IP アドレスブロック、またはグローバル IP ブロックなど、任意の IPv4 アドレス範囲から、VPC のアドレス指定を行うことができます。パブリックにルーティング可能な IP ブロックには、仮想プライベートゲートウェイ経由でのみ到達可能であり、インターネットゲートウェイを通してインターネット経由でアクセスすることはできません。AWS 側では、お客様が所有している IP アドレスブロックをインターネット上で公開しません。また、VPC は現在、IPv6 IP アドレス範囲からアドレス指定を行うことはできません。

http://aws.amazon.com/jp/vpc/faqs/#I1

ところで、念のため補足しておきますが、AWSでは、グローバル部分については、ELBがIPv6をサポートしています。
参考: Amazon Web Services ブログ: 【AWS発表】 Elastic Load Balancingが東京リージョンでIPv6をサポート、新メトリクスもサポート、複数のIPアドレスを返すように


で、話は戻って、IPv4/IPv6を共存させるためのソリューションはいくつかあって、

ちょっと古いですが、上記のページとかは「トンネリング」「デュアルスタック」「トランスレータ」などの説明があって、わかりやすい。


さて、どうしようかと、Amazon VPCインターナルでのIPv6利用事例をインターネットで検索するも、めぼしい情報が見当たらなくて、一旦、この件を、AWSのソリューションアーキテクトの方に相談したところ、より運用がシームレスかつ、GUAを柔軟に割り振れる、自動トンネリングパターンの1つである"6rd"がいいのではないかと、ご提案をいただきました。

6rdとは

"6rd"とは、IPv6での通信をIPv4網で転送するための自動トンネル技術の1つです。

6rdに関しては解説サイトがいくつかあるので、そちらを引用させていただきます。

「6rd(IPv6 rapid deployment)」とは、IPv6接続を実現する方式の一つ。IPv4ネットワークの上にIPv6パケットを流すトンネリング技術で、インターネットの標準化組織であるIETFで仕様策定が進んでいる。

ユーザー宅内に設置した6rd対応のネットワーク機器(CPE:Customer Premises Equipment)と、プロバイダーのネットワークに設置した6rd対応リレールーター(6rd Border Relay)の間にトンネルを形成し、IPv6パケットを転送する。エンドユーザー宅内と、アクセス先のサーバーなどが置いてあるネットワークはIPv6 に対応しているが、プロバイダー側にはIPv4ネットワークが残っている環境を想定した技術である(図)。

IPv6 over IPv4トンネリング技術はほかにもあるが、6rdは実装が比較的容易で、コスト負担が小さいといわれる。

具体的に、(1)既存のIPv4ネットワークに大きな変更を加えず、リレールーターを追加するだけでIPv6接続を実現できる、(2)他のトンネル方式に比べてユーザーを収容する際の効率が良い、(3)6rdではIPv4アドレスからIPv6アドレスを生成するため、新たなアドレス配布システムが必要ない、(4)リレールーターはプロバイダーごとに異なるIPv6プレフィックス(アドレスの一部)を配布するため、経路を制御しやすい──というメリットがある。

6rd | 日経 xTECH(クロステック)


他、仕組みや勘所を理解するためには、以下のリンクが参考になります。

構成案

さて、以下が今回の構成案です。

青い太線がIPsecトンネル。緑の太線が6rdのトンネルです。


今回は、Customer Gatewayに、前回のエントリ同様にCisco 1921シリーズのルーターを使って、AWS側のVPN GatewayとIPsecトンネルをはります。さらにCustomer Gateway自体を、6rdでいうBR(Border Relay)の役割を果たすリレールーターとして使います。

その先のAmazon VPC網内もIPv4で構成されたネットワーク環境のため、EC2インスタンスまで6rdプロトコルのトンネルを伸ばすことで、EC2インスタンスのサーバ自身が6rdでいうCE(Customer Edge)となります。こうすることで、EC2インスタンスにIPv6のアドレスを持ったトンネルインターフェースを生成できます。
このため、6rdによるトンネリングは各インスタンス(CE)ごとに張られることになります。


こういった構成を組むことで、サーバ同士がIPv6で会話できるようになります。

6rdを組むパターンでは、CEとしてはルータを配置し、そのBRとCEで6rdトンネルを一本張って運用することが多いようですが、今回のAWS(VPC)を使った構成では各サーバをCEとして、それぞれでトンネリングする形です。(6rdトンネルは、機種によるそうですが、そもそもステートレスなプロトコルなので、かなりのトンネル数を生成しても問題なさそうで、基本的にはトラフィックバウンドとのこと。)

BRの設定(Ciscoルータ)

下記のCiscoのドキュメントを参考に設定しました。


Customer Gatewayとなるルータに、最終的に入れた設定は以下です。

ipv6 unicast-routing
!
interface GigabitEthernet 0/1
  ipv6 address 2xxx:xxxx:xxxx:f013::110/64
end
!
interface loopback 1
  ip address 10.255.255.222 255.255.255.255
end
!
interface Tunnel0
  ipv6 address 2xxx:xxxx:xxxx:f096:0aff:ffde::1/96
  tunnel source loopback 1
  tunnel mode ipv6ip 6rd
  tunnel 6rd prefix 2xxx:xxxx:xxxx:f096::/64
end
!
ipv6 route 2xxx:xxxx:xxxx:F096:AFF:FFDE::/96 Null0
ipv6 route 2xxx:xxxx:xxxx:F096::/64 Tunnel0

上から、簡単に解説すると、

  • IPv6のルーティングを有効に。
  • 自ネットワークにあるルータなので、LAN側にIPv6アドレスを付与。
  • ループバックアドレスを設定。
    • 6rdトンネルのsource用に。今回の構成ではそれほど恩恵は無いが、論理インターフェースを指定。
  • トンネルのインターフェースを指定。
    • 先程設定したループバックアドレスから、IPv6アドレスを付与。(算出方法は後述)
    • ソースアドレスを先程設定したループバックアドレスを指定。
    • VPC側のインスタンスに付与されるIPv6アドレスのプレフィックスを指定。
      • (任意、というか6rdトンネルで利用したい適切なネットワークアドレス帯を指定します)
  • IPv6用のルーティングを設定。


ちなみに、ループバックアドレス(今回の例では、10.255.255.222)を基にして、6rdのアドレスマッピングルールから算出したIPv6アドレスは以下です。

$ printf "2xxx:xxxx:xxxx:f096:%02x%02x:%02x%02x::1" 10 255 255 222
2xxx:xxxx:xxxx:f096:0aff:ffde

IPv4アドレスを16進数表記に変更したものを埋め込んでいます。
"2xxx:xxxx:xxxx:f096"の部分については、先程トンネルのインターフェースで指定した6rdで使うIPv6アドレスのプレフィックスを指定します。

CEの設定(Amazon EC2インスタンス/Amazon Linux)

続いて、CEとなる設定を、Amazon VPC内で起動したEC2インスタンスに入れていきます。
これを入れることで、BRルータと6rdプロトコルを使った通信が可能になります。(IPv6がしゃべれる)


ちなみに、Linuxで6rdプロトコルをしゃべるためには、Kernelのバージョンが2.6.33以降で、"CONFIG_IPV6_SIT_6RD"がyとなっている必要があります。

# uname -r
3.4.43-43.43.amzn1.x86_64
# grep 6RD /boot/config-`uname -r`
CONFIG_IPV6_SIT_6RD=y

今回、使ったAmazon Linuxでは、上記の通りデフォルトで利用できる状態でした。

$ printf "2xxx:xxxx:xxxx:f096:%02x%02x:%02x%02x::1" 10 96 1 100
2xxx:xxxx:xxxx:f096:0a60:0164::1

まずは、先程のBR同様に、IPv6アドレスを算出します。
(今回の例では、このCEとなるEC2インスタンスに紐付くIPv4アドレスは"10.96.1.100"となっています。)

# cat /etc/sysconfig/network-scripts/ifcfg-sit1
DEVICE=sit1
IPV6INIT=yes
IPV6_MTU=1280
IPV6_DEFAULTGW=::10.255.255.222
IPV6TUNNELIPV4=any
IPV6TUNNELIPV4LOCAL=10.96.1.100
IPV6ADDR=2xxx:xxxx:xxxx:f096:0a60:0164::1/96

トンネル用のIPv6インターフェースを"/etc/sysconfig/network-scripts/ifcfg-sit1"に、こんな感じでデバイスを作ります。
このとき、デフォルトゲートウェイを、BRで設定した6rdで使うソースアドレスと一致させておきましょう。
(6rdでは、通信そのものはIPv4で行うため、ゲートウェイの指定はIPv4アドレスです。)

# cat /etc/rc.d/rc.local

〜〜〜省略〜〜〜

ip tunnel 6rd dev sit1 6rd-prefix 2xxx:xxxx:xxxx:f096::/64 6rd-relay_prefix 10.96.1.100/32

"/etc/rc.d/rc.local"では、先ほど定義したトンネルデバイス(sit1)に、6rdで使うプレフィックスの設定を入れます。(ちなみに、Amazon LInuxでは、この設定を入れなくても軽く動作確認する感じでは問題なく動いていました。ひょっとしたら要らないかも。)
6rd-prefixは、先ほどBRで設定したものと同じ、6rdで利用するIPv6のプレフィックスを入れます。
6rd-relay_prefixは、アドレスマッピングルールとして、IPv4アドレスの何ビット分を埋め込むかを指定します。今回の例では、32ビット分全てを埋め込んでいますので、上記のような指定としています。


ここで、一度設定を反映させるために、OSをリブートします。

# ifconfig sit1
sit1      Link encap:IPv6-in-IPv4
          inet6 addr: 2xxx:xxxx:xxxx:f096:a60:164:0:1/96 Scope:Global
          inet6 addr: ::10.96.1.100/128 Scope:Compat
          UP RUNNING NOARP  MTU:1280  Metric:1
          RX packets:262 errors:0 dropped:0 overruns:0 frame:0
          TX packets:262 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:17292 (16.8 KiB)  TX bytes:14672 (14.3 KiB)

# ip tunnel show
sit0: ipv6/ip  remote any  local any  ttl 64  nopmtudisc 6rd-prefix 2002::/16
sit1: ipv6/ip  remote any  local 10.96.1.100  ttl 64  6rd-prefix 2xxx:xxxx:xxxx:f096::/64 6rd-relay_prefix 10.96.1.100/32

# ip -6 route show | grep default
default via ::10.255.255.222 dev sit1  metric 1

起動後に、設定が反映されているか確認します。
ポイントは、トンネルデバイスに意図したIPv6アドレスが振られているか、IPv6のデフォルトルートがBRルータ(今回の例では、BRの論理インターフェース)を向いているか、あたりです。

動作確認

簡易的ではありますが、双方からpingで疎通してみましょう。

from AWS

VPC-Server$ ping6 -c 3 2xxx:xxxx:xxxx:100:5054:1cff:fe93:3ea8
PING 2xxx:xxxx:xxxx:100:5054:1cff:fe93:3ea8(2xxx:xxxx:xxxx:100:5054:1cff:fe93:3ea8) 56 data bytes
64 bytes from 2xxx:xxxx:xxxx:100:5054:1cff:fe93:3ea8: icmp_seq=1 ttl=62 time=6.17 ms
64 bytes from 2xxx:xxxx:xxxx:100:5054:1cff:fe93:3ea8: icmp_seq=2 ttl=62 time=6.21 ms
64 bytes from 2xxx:xxxx:xxxx:100:5054:1cff:fe93:3ea8: icmp_seq=3 ttl=62 time=6.17 ms

--- 2xxx:xxxx:xxxx:100:5054:1cff:fe93:3ea8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2009ms
rtt min/avg/max/mdev = 6.172/6.187/6.213/0.092 ms

from Customer Network

Local-Server$ ping6 -c 3 2xxx:xxxx:xxxx:f096:a60:164:0:1
PING 2xxx:xxxx:xxxx:f096:a60:164:0:1(2xxx:xxxx:xxxx:f096:a60:164:0:1) 56 data bytes
64 bytes from 2xxx:xxxx:xxxx:f096:a60:164:0:1: icmp_seq=1 ttl=62 time=6.31 ms
64 bytes from 2xxx:xxxx:xxxx:f096:a60:164:0:1: icmp_seq=2 ttl=62 time=6.28 ms
64 bytes from 2xxx:xxxx:xxxx:f096:a60:164:0:1: icmp_seq=3 ttl=62 time=6.33 ms

--- 2xxx:xxxx:xxxx:f096:a60:164:0:1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2009ms
rtt min/avg/max/mdev = 6.280/6.308/6.334/0.068 ms


この通り、疎通できました。


疎通できなかった場合は、、、

  • IPv4/IPv6ともに、各経路上でルーティングが正しく設定されているか
  • トンネルインターフェースにもきちんとIPv6アドレスが振られているか
  • トンネルのソースアドレスが到達可能なIPv4アドレスになっているか

等々を見直すと良いかもしれません。
基本的には、pingでの動作確認であれば、tcpdumpとかで、どこまでICMPパケットが到達しているかわかるので、各経路1つずつでチェックしていくと何か原因がつかめると思います。


まだ続編があるのですが、ちょっと長くなってしまったので、今回はここまで。
それでは!=͟͟͞͞(๑•̀=͟͟͞͞(๑•̀д•́=͟͟͞͞(๑•̀д•́๑)=͟͟͞͞(๑•̀д•́

謝辞

今回の試行を行う上で、さくらインターネットさんとCiscoさんのサイトでの6rdの設定例および解説が大変参考になりました。


また、IPv6 on Amazon VPCをやってみる上で、AWS社のソリューションアーキテクトである荒木氏(@ar1)には、有用なアドバイスを頂きました。
この場を借りてお礼申し上げます。




まとめ


クラウドAMAZON EC2/S3のすべて (ITpro BOOKs)

クラウドAMAZON EC2/S3のすべて (ITpro BOOKs)

マスタリングTCP/IP IPv6編 第2版

マスタリングTCP/IP IPv6編 第2版