こんにちは、SCSKでAWSの内製化支援『テクニカルエスコートサービス』を担当している貝塚です。
AWSサービスに接続するためのVPCエンドポイント(ssm.ap-northeast-1.amazonaws.com など)がVPCごとに作られていくのは管理上よろしくないと考える方はいらっしゃるようでして、VPCエンドポイントを1か所に集中させたいというご要望を頂くことがございます。
これを実現するうえで重要なのは、DNS名前解決をどのように行うか、です。本稿では、マルチアカウント環境において、AWSサービス用のVPCエンドポイント(ssm.ap-northeast-1.amazonaws.com など)を一つのVPCに集約した場合のDNS名前解決パターンについて考察します。
プライベートホストゾーンを使う案
対象ドメイン(例:ap-northeast-1.amazonaws.com)のプライベートホストゾーンを作成し、各アカウント・各VPCに関連付けることで、ハブVPC上のVPCエンドポイントの名前が返るようにします。
アーキテクチャ図は以下の通りです。
プライベートホストゾーンではハブVPC上のDNS名とIPアドレスを対応付けるAレコードを作成しておきます。スポークVPCでAmazon Provided DNS(デフォルトで設定されるDNS)にDNSクエリを発行すると、プライベートホストゾーンに登録されたハブVPC上のIPアドレスが返ってきます。
こちらの構成は、クラスメソッドさんの下記記事で既に解説されていますので、本稿では気づいた点を何点か述べるに留めます。
- ap-northeast-1.amazonaws.com や amazonaws.com でプライベートホストゾーンを作成しようとすると、既にAWSに予約されているという理由でエラーになるので、bedrock.ap-northeast-1.amazonaws.com や kendra.ap-northeast-1.amazonaws.com のようにサービス名ごとにプライベートホストゾーンを作成する必要がある。
- プライベートホストゾーンを他アカウントのVPCに関連付ける作業はマネジメントコンソールからは実行できず、CLI等から実施する必要がある。
- 名前解決したいホスト名の数 × 関連付けたいVPCの数 だけ関連付け作業を実施する必要があるので、規模が多くなってきたらスクリプト化・IaC化必須である。
プライベートホストゾーン設定例(kendra.ap-northeast-1.amazonaws.comゾーンのレコード作成)
他のアカウントのVPCにプライベートホストゾーンを関連付ける手順についても以下のクラスメソッドさんの記事で解説されていますので、そちらをご参照ください。
なお、この手順で関連付けられたホストゾーンは、マネジメントコンソールから確認することができず、CLIの route53 list-hosted-zones-by-vpc などで確認する必要があるようです。
DHCPオプションセットを使う案
スポークVPCにDHCPオプションセットを適用して、(EC2などが)参照するDNSサーバのIPアドレスにハブVPC上のRoute 53 Resolverインバウンドエンドポイントを指定する方法です。
アーキテクチャ図を描くと以下の通りです。
こちらも先ほどご紹介したクラスメソッドさんの記事で既に解説されていますので、本稿では詳しい説明を割愛します。
- ハブVPC内のRoute 53 Resolverインバウンドエンドポイントは、同じVPC内にあるVPCエンドポイント(この例の場合は bedrock.ap-northeast-1.amazonaws.com)の名前解決時にプライベートIPアドレスを返しますので、プライベートホストゾーンを作成する必要はありません。
- スポークVPC(内のEC2等)が参照するDNSサーバがハブVPC上にあるため、スポークVPC独自の名前解決をさせたいときに難易度が上がります。例えばできる限りSession Managerがネットワーク障害の影響を受けないようにする目的で、Session Manager用のVPCエンドポイントだけはスポークVPC内に作成したい(他のVPCエンドポイントはハブVPC内に置きたい)となった場合に、対応ができません。
スポークVPCにRoute 53リゾルバ アウトバウンドエンドポイントを置く案
私が無い知恵をふりしぼって最初に考えた構成です。ハブVPCにRoute 53リゾルバ インバウンドエンドポイントを作成し、スポークVPCにはRoute 53リゾルバ アウトバウンドエンドポイントを作成します。スポークVPCで発行されたap-northeast-1.amazonaws.comドメインのDNSクエリは、リゾルバ転送ルールを使用してハブVPCのインバウンドエンドポイント(のIPアドレス)に向けてやります。
図にするとこのようになります。
この構成は動作します。しかし、VPCごとにRoute 53リゾルバ アウトバウンドエンドポイントが必要になり、冗長構成が必須であることも考慮するとそれだけで月180ドルの料金がかかってしまいますので、今回の目的に照らし合わせると没案と言わざるを得ません…。
Resource Access Managerでリゾルバルールを共有する案
私が費用対効果の悪い案をひねり出すより前に、AWSからとっくに以下のようなアーキテクチャが公開されていました。
リンク先にも示されていますが図にすると以下のようになります。(リンク先とは図が若干異なりますが、私なりに同じものをより分かりやすく示そうとした結果です)
構成を細かく分解して説明すると以下の通りです。
- ハブVPCに、Route 53リゾルバ インバウンドエンドポイントだけではなく、Route 53リゾルバ アウトバウンドエンドポイントも作成する
- リゾルバ転送ルールを作成し、ap-northeast-1.amazonaws.comドメインの名前解決をRoute 53リゾルバ インバウンドエンドポイント(のIPアドレス)に転送するように設定する
- リゾルバ転送ルールをResource Access Manager (RAM)を使ってスポークアカウントと共有する
- スポークアカウント側で、リゾルバ転送ルールをスポークVPCに関連付ける
上記の通り構成することで、スポークVPC側にRoute 53リゾルバ アウトバウンドエンドポイントがなくても、Amazon Provided DNSは、ap-northeast-1.amazonaws.comドメインの名前解決DNSクエリを ハブVPCのRoute 53リゾルバ インバウンドエンドポイントへと転送してくれます。
構築時のポイント
ハブアカウント側、リゾルバ転送ルールの作成
今回の目的は、ap-northeast-1.amazonaws.comドメイン(AWSサービスのVPCエンドポイント)の名前解決をハブVPCに転送することなので、ルールの作成画面でドメイン名にap-northeast-1.amazonaws.comを指定します。
VPCは指定する必要がありません。
ターゲットIPアドレスに、Route 53リゾルバ インバウンドエンドポイントのIPアドレスを指定します。
Resource Access Manager (RAM)を使用した転送ルールの共有
Resource Access Manager (RAM)メニューの「自分が共有: リソース共有」から「リソース共有を作成」ボタンを押します。
そこから先の設定は、以下にスクリーンショットを載せました。
「リソース – オプション」のところで「リゾルバルール」を選び、対象のルールをチェックします。
マネージド型アクセス許可は、デフォルトのまま変更しませんでした。
プリンシパルタイプは、「AWSアカウント」を選択し、スポークアカウントのアカウントIDを入力します。
また、スクリーンショットは載せていませんが、スポークアカウント側でResource Access Manager (RAM)メニューの「自分と共有: リソース共有」から「リソース共有を承認」する必要があります。
リゾルバ転送ルールをスポークVPCに関連付け
共有された転送ルールは、Route 53 > リゾルバー > ルール のルール詳細から、「VPCを関連付ける」をクリックし、スポークVPCを関連付けます。
名前解決確認
以上で設定は完了です。スポークVPCのEC2からdigコマンドでssm.ap-northeast-1.amazonaws.comの名前解決を実行すると、ハブVPCのssmエンドポイントのIPアドレスが返ってきました。
DNSクエリの通信経路はどうなっている?
この構成で、DNSクエリ(UDP 53番ポートの通信)は実際にどのように行われているのでしょうか。調べてみることにします。
この構成なら、スポークVPCのAmazon Provided DNS(10.1.0.2)からRoute 53リゾルバ インバウンドエンドポイント(10.0.33.153, 10.0.34.129)へのIP通信が発生しているのではないか?と推測しました。
しかし、DNSクエリログと照らし合わせながらVPCフローログを調べて行きますが、スポークアカウント側に該当するログはありません。それどころか該当の時間帯に、UDP 53番ポートの通信は一切発生していませんでした。
次に、ハブアカウントを見ていきます。
ハブアカウント側のDNSクエリログを見ると、上記と同時刻に同内容のDNSクエリが確認できるので、スポークVPCで発生したDNSクエリが、ハブVPCまで到達し、ハブVPC側で応答を返したと考えられます。以下がそのログです。
ハブアカウント側のVPCフローログも調べて行きます。スポークVPCからのUDP 53番ポート通信は発見できませんでしたが、該当時間帯に以下のログを発見しました。
DNSクエリログのタイムスタンプと若干ずれがありますが、srcPortが一致(46161)していることから、同じ通信のことを指しているとみて間違いないでしょう。
srcAddrの10.0.34.254は、Route 53リゾルバ アウトバウンドエンドポイントのIPアドレス(のひとつ)です。スポークVPCで発生したDNSクエリは、Route 53リゾルバ アウトバウンドエンドポイントで一種のNATのようなものが行われてハブVPCにやって来たと推測できます。
dstAddrの10.0.34.129は、Route 53リゾルバ インバウンドエンドポイントのIPアドレス(のひとつ)です。ここまで到達して、Route 53による名前解決が行われたと考えられます。
以上の情報をまとめると、下図青色実線矢印の通信が確認できたことになります。
青色破線矢印の部分がどのように行われたか、ですが、VPC側のフローログを確認しても該当するログは発見できませんでしたので、AWSインフラ側を通る通信であり、ユーザ側(VPC)からは見えないようになっているのだと考えられます。
まとめ
本稿では、AWSサービス用VPCエンドポイントをひとつのVPCに集約したい場合のDNS名前解決アーキテクチャとして以下の4つを概観しました。
- プライベートホストゾーンを使う案
- DHCPオプションセットを使う案
- スポークVPCにRoute 53リゾルバ アウトバウンドエンドポイントを置く案
- Resource Access Managerでリゾルバルールを共有する案
また、第4案について、構築時のポイントを解説するとともに、DNSクエリの通信を追ってみた結果、通信の一部がAWSインフラ側を通っていると考えられることを示しました。
本稿の内容がDNS設計のお役に立てば幸いです。