[M5/C5] VPC ピアリングに隠された Nitro 世代 EC2 と PrivateLink の不思議な関係
こんにちは、菊池です。
先日、PrivateLinkを使ったVPCエンドポイント(インターフェースエンドポイント)について公式ドキュメントを見ていたところ、気になる記述を発見しました。
インターフェイスエンドポイントのプロパティと制限
インターフェイスエンドポイントを使用するには、そのプロパティと現在の制限に注意する必要があります。
- インターフェイスエンドポイントには、AWS Direct Connect 接続を通じてアクセスできます。また、C5 および M5 インスタンスタイプのみからリージョン内 VPC ピア接続を介してアクセスできます。C5 または M5 以外のインスタンスタイプから、AWS VPN 接続、リージョン間 VPC ピア接続、またはリージョン内 VPC ピア接続を介してインターフェイスエンドポイントにアクセスすることはできません。
「C5 および M5 インスタンスタイプのみからリージョン内 VPC ピア接続を介してアクセスできます。」
つまり、VPCピアリングを経由したインターフェースエンドポイントの利用可否が、インスタンスタイプによって異なるということです。ここでアクセス可能とされる C5、M5インスタンスは、Nitro Systemというハイパーバイザーを搭載した最新世代のインスタンスタイプです。Nitro Systemについての詳細は以下を参照ください。
インスタンスタイプによってVPCコンポーネントへのアクセス可否が異なるという仕様は、把握していないと思わぬハマりどころになりそうです。
VPCピアリング経由でインターフェースエンドポイントにアクセスしてみる
実際に、以下のようにm5.largeとm4.largeのインスタンスを使って、VPCピアリングを経由したKinesis Streamsへのインターフェースエンドポイントへアクセスして試してみます。ドキュメントの通りであれば、m5.largeからのみアクセスできるはずです。
まずは、2つのVPCをピアリングします。
次に、片方のVPC(CIDR:10.0.0.0/16)にKinesis StreamsのVPCエンドポイントを作成しました。
VPCピアリング経由でのインターフェースエンドポイントの名前解決
インターフェースエンドポイント(PrivateLink)では、対象のAWSサービスのエンドポイントの名前解決で、VPC内のプライベートIPを返すことでアクセスできます。今回の場合、Kinesis Streamsのエンドポイントであるkinesis.ap-northeast-1.amazonaws.com
の名前解決で取得するIPが、10.0.0.xxxになることとで、インターネットを経由しないプライベートな経路でのアクセスが可能です。
ということで、まずは2つのインスタンスからエンドポイントのIPを引いてみます。
- m5.large
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | [ec2-user@ip-172-16-0-66 ~]$ curl http: //169 .254.169.254 /latest/meta-data/instance-type m5.large [ec2-user@ip-172-16-0-66 ~]$ dig kinesis.ap-northeast-1.amazonaws.com @172.16.0.2 ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.57.amzn1 <<>> kinesis.ap-northeast-1.amazonaws.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id : 12763 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;kinesis.ap-northeast-1.amazonaws.com. IN A 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ;; ANSWER SECTION: kinesis.ap-northeast-1.amazonaws.com. 23 IN A 54.240.225.127 ;; Query time : 0 msec ;; SERVER: 172.16.0.2 #53(172.16.0.2) ;; WHEN: Sat May 26 03:34:47 2018 ;; MSG SIZE rcvd: 70 |
- m4.large
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | [ec2-user@ip-172-16-0-104 ~]$ curl http: //169 .254.169.254 /latest/meta-data/instance-type m4.large [ec2-user@ip-172-16-0-104 ~]$ dig kinesis.ap-northeast-1.amazonaws.com @172.16.0.2 ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.57.amzn1 <<>> kinesis.ap-northeast-1.amazonaws.com ;; global options: +cmd 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id : 40862 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;kinesis.ap-northeast-1.amazonaws.com. IN A ;; ANSWER SECTION: kinesis.ap-northeast-1.amazonaws.com. 24 IN A 52.95.34.163 ;; Query time : 2 msec ;; SERVER: 172.16.0.2 #53(172.16.0.2) ;; WHEN: Sat May 26 03:36:34 2018 ;; MSG SIZE rcvd: 70 |
どちらも、PublicIPが取得されました。一方で、VPCエンドポイント固有のDNS名である、vpce-01168adb08a47a58c-oz584kry.kinesis.ap-northeast-1.vpce.amazonaws.com
を引いてみます。
- m5.large
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [ec2-user@ip-172-16-0-66 ~]$ dig vpce-01168adb08a47a58c-oz584kry.kinesis.ap-northeast-1.vpce.amazonaws.com @172.16.0.2 ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.57.amzn1 <<>> vpce-01168adb08a47a58c-oz584kry.kinesis.ap-northeast-1.vpce.amazonaws.com @172.16.0.2 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id : 57515 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;vpce-01168adb08a47a58c-oz584kry.kinesis.ap-northeast-1.vpce.amazonaws.com. IN A ;; ANSWER SECTION: vpce-01168adb08a47a58c-oz584kry.kinesis.ap-northeast-1.vpce.amazonaws.com. 60 IN A 10.0.0.238 ;; Query time : 32 msec ;; SERVER: 172.16.0.2 #53(172.16.0.2) ;; WHEN: Sat May 26 04:28:12 2018 ;; MSG SIZE rcvd: 107 |
- m4.large
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [ec2-user@ip-172-16-0-104 ~]$ dig vpce-01168adb08a47a58c-oz584kry.kinesis.ap-northeast-1.vpce.amazonaws.com @172.16.0.2 ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.57.amzn1 <<>> vpce-01168adb08a47a58c-oz584kry.kinesis.ap-northeast-1.vpce.amazonaws.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id : 1933 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;vpce-01168adb08a47a58c-oz584kry.kinesis.ap-northeast-1.vpce.amazonaws.com. IN A ;; ANSWER SECTION: vpce-01168adb08a47a58c-oz584kry.kinesis.ap-northeast-1.vpce.amazonaws.com. 60 IN A 10.0.0.238 ;; Query time : 5 msec ;; SERVER: 172.16.0.2 #53(172.16.0.2) ;; WHEN: Sat May 26 03:37:01 2018 ;; MSG SIZE rcvd: 107 |
こちらは、どちらのインスタンスタイプでも、PrivateIPである10.0.0.238
を取得できました。
インターフェースエンドポイントでは、VPC内のAmazon DNSがエンドポイントの名前解決でPrivateIPを返すことで実現されます。しかし、以下のようにAmazon DNSでは自VPC内からのみ利用可能なため、VPCピアリングを経由しての利用はできません。
そのため、EC2のあるVPCからの名前解決では、PublicにあるエンドポイントのIPを返してしまっているようです。これは、VPCピアリング間のDNS名前解決を有効にしても同様の結果でした。
エンドポイント独自のDNS名を使うことで、インターフェースエンドポイントへアクセスすることはできそうですが、それではCLIやSDKを使っての利用に支障があります。そこで、VPCピアリング経由でのAmazon DNSを使った名前解決を可能にするため、以下のようにSimpleADをDNSキャッシュサーバとして中継させる構成を利用します。
サクッとSimpleADを立ち上げ、そのIPをDNSとして設定します。
これで、再度kinesis.ap-northeast-1.amazonaws.com
を引いてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | [ec2-user@ip-172-16-0-66 ~]$ curl http: //169 .254.169.254 /latest/meta-data/instance-type m5.large [ec2-user@ip-172-16-0-66 ~]$ dig kinesis.ap-northeast-1.amazonaws.com @10.0.0.50 ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.57.amzn1 <<>> kinesis.ap-northeast-1.amazonaws.com @10.0.0.50 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id : 40181 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;kinesis.ap-northeast-1.amazonaws.com. IN A ;; ANSWER SECTION: kinesis.ap-northeast-1.amazonaws.com. 60 IN A 10.0.0.238 ;; Query time : 2 msec ;; SERVER: 10.0.0.50 #53(10.0.0.50) ;; WHEN: Sat May 26 04:53:24 2018 ;; MSG SIZE rcvd: 81 |
VPCピアリング経由でkinesis.ap-northeast-1.amazonaws.com
のインターフェースエンドポイントのIPが取得できました。
インターフェースエンドポイントにアクセスする
それでは、いよいよm5.large、m4.largeの各インスタンスからインターフェースエンドポイントにアクセスします。
- m5.large
1 2 3 4 5 6 | [ec2-user@ip-172-16-0-66 ~]$ curl http: //169 .254.169.254 /latest/meta-data/instance-type m5.large [ec2-user@ip-172-16-0-66 ~]$ aws kinesis list-streams --region ap-northeast-1 { "StreamNames" : [] } |
- m4.large
1 2 3 4 5 | [ec2-user@ip-172-16-0-104 ~]$ curl http: //169 .254.169.254 /latest/meta-data/instance-type m4.large [ec2-user@ip-172-16-0-104 ~]$ aws kinesis list-streams --region ap-northeast-1 HTTPSConnectionPool(host= 'kinesis.ap-northeast-1.amazonaws.com' , port=443): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<botocore.awsrequest.AWSHTTPSConnection object at 0x7f9f2b78d450>, 'Connection to kinesis.ap-northeast-1.amazonaws.com timed out. (connect timeout=60)' )) |
仕様通りの結果となりました!
m5.largeではKinesis Streamsへアクセスしレスポンスが取得できています。一方で、m4.largeのインスタンスからはアクセスできず、タイムアウトとなっています。
独自エンドポイント(エンドポイントサービスの場合)
これまでは、AWSのエンドポイントで試してみましたが、インターフェースエンドポイントでは、独自のサービスも公開可能です。こちらでも同様に試してみました。
以下のように、別のVPCにNLB(Network Load Balancer)とEC2でWEBサーバを公開します。
エンドポイントサービスを公開し、エンドポイントを作成します。
作成されたエンドポイント名の名前を引いてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [ec2-user@ip-172-16-0-66 ~]$ dig vpce-076d2b5f8871bc4ab-loqhn66m.vpce-svc-0dd0229a2b6117342.ap-northeast-1.vpce.amazonaws.com @172.16.0.2 ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.57.amzn1 <<>> vpce-076d2b5f8871bc4ab-loqhn66m.vpce-svc-0dd0229a2b6117342.ap-northeast-1.vpce.amazonaws.com @172.16.0.2 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id : 29193 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;vpce-076d2b5f8871bc4ab-loqhn66m.vpce-svc-0dd0229a2b6117342.ap-northeast-1.vpce.amazonaws.com. IN A ;; ANSWER SECTION: vpce-076d2b5f8871bc4ab-loqhn66m.vpce-svc-0dd0229a2b6117342.ap-northeast-1.vpce.amazonaws.com. 60 IN A 10.0.0.122 ;; Query time : 32 msec ;; SERVER: 172.16.0.2 #53(172.16.0.2) ;; WHEN: Sat May 26 04:41:34 2018 ;; MSG SIZE rcvd: 126 |
こちらの場合は、完全に固有のエンドポイント名となり、Publicに名前を引いてもPrivateIPが取得できるため、名前解決に困ることはなさそうです。
では、エンドポイントサービスにアクセスしてみます。
- m5.large
1 2 3 4 | [ec2-user@ip-172-16-0-66 ~]$ curl http: //169 .254.169.254 /latest/meta-data/instance-type m5.large [ec2-user@ip-172-16-0-66 ~]$ curl vpce-076d2b5f8871bc4ab-loqhn66m.vpce-svc-0dd0229a2b6117342.ap-northeast-1.vpce.amazonaws.com Hello |
- m4.large
1 2 3 4 | [ec2-user@ip-172-16-0-104 ~]$ curl http: //169 .254.169.254 /latest/meta-data/instance-type m4.large [ec2-user@ip-172-16-0-104 ~]$ curl vpce-076d2b5f8871bc4ab-loqhn66m.vpce-svc-0dd0229a2b6117342.ap-northeast-1.vpce.amazonaws.com curl: (7) Failed to connect to vpce-076d2b5f8871bc4ab-loqhn66m.vpce-svc-0dd0229a2b6117342.ap-northeast-1.vpce.amazonaws.com port 80: 接続がタイムアウトしました |
こちらも、m5.largeではVPCピアリングを経由したインターフェースエンドポイントにアクセスができました。やはり、m4.largeではアクセスできない結果となっています。
まとめ
ドキュメントの記載を見つけたとき、そんな仕様があるのかと驚きました。Nitroハイパーバイザで動作するインスタンスでは、一部の制約から解放されるという動きがあるようです。
とはいえ、現時点では名前解決も含め、VPCピアリング経由でのインターフェースエンドポイントへのアクセスを実運用に持ち込むのは少しリスクを感じます。インスタンスの追加やインスタンスタイプの変更で、うっかりM5/C5以外を選択してしまうのと、設計が破綻してしまうようなこともあり得るからです。
逆に、今後さらに新しいインスタンスタイプが登場し、あらゆるインスタンスタイプでNitroハイパーバイザが一般化すると、現状あるVPCの多くの制約が取り払われて行くのではないかと期待が持てる仕様と思います。