
プライベートDNS付きVPC Interface Endpointだけでは、リージョン間のS3アクセスが成立しない理由を実例で解説します
背景
AWSのドキュメントには書かれていませんが、バケットがないリージョン側(私の例ならus-west-2)でS3への接続を少しだけ追加しないと、この方法は動きません。詳しくは実装手順のステップ6で取り上げます。
シナリオ
この制約があるのは、AWSのVPCエンドポイントが同一リージョン内のサービスへのプライベート接続を提供する目的で設計されているためです。
ソリューションアーキテクチャ
構成要素
- VPC B:S3 Interface Endpointを配置する
us-east-1の新規または既存のVPC - VPCピアリング接続:2つのVPCを橋渡しする接続
- Private Hosted Zone:S3エンドポイントを正しく名前解決するためのRoute53 DNS
- S3 VPC Interface Endpoint:エンドポイントの実体は、対象VPC内のElastic Network Interface(ENI)です。AWSのバックボーンネットワーク経由でS3へのプライベートかつセキュアな接続を提供します(今回のケースでは
us-east-1に配置)
実装ステップ
前提条件
ステップ1:S3エンドポイントのセキュリティ設定
ステップ2:S3 VPC Interface Endpointの作成
- プライベートDNSは無効化
- 事前に作成しておいた
VPC_B_S3_SGセキュリティグループをアタッチ
ステップ3:VPCピアリングの確立
ステップ4:PHZでDNS解決を構成
us-west-2のVPC Aを新しいPHZに関連付ける
このPHZ内に、S3 VPC Interface Endpointの**リージョナルDNS名***を指すAlias Aレコードを2つ作成します。
1. ルートレコード:レコード名は空欄のままにして、次のレコードを作成します。
s3.us-east-1.amazonaws.com
ルートレコード — レコード名は空欄のまま
2. ワイルドカードレコード:レコード名に*を指定し、次を処理させます。
*.s3.us-east-1.amazonaws.com
キャッチオール — レコード名に「*」を入力
\* リージョナルDNS名とは、アベイラビリティゾーンの指定を含まない名前のことです。
形式は次のようになります。
`*.vpce-0123456789abcdefg-dawd972fe.s3.us-east-1.vpce.amazonaws.com
であって、 us-east-1` a(こちらはゾーナルDNS名)ではありません。
ゾーナルDNS名は、アベイラビリティゾーン単位でworkloadsを分離するアーキテクチャで役立ちます。たとえば、トラフィックをInterface EndpointのENIと同じAZ・同じリージョン内に閉じ込めることで、リージョン内のデータ転送コストを抑えられます。ただし、このメリットが得られるのは同一リージョン・同一AZでのアクセスに限られ、リージョンをまたぐシナリオでは活きません。
作成後のレコード:
新しいPHZに作成されたレコード
ステップ5:ルーティングの設定
- VPC A:EC2インスタンスが稼働しているサブネットのルートテーブルに、VPC BのCIDRブロック宛のトラフィックをピアリング接続経由で転送するルールを追加します
- VPC B:VPC Interface Endpointを配置したサブネットのルートテーブルに、VPC AのCIDRブロック宛のトラフィックを同じピアリング接続経由で転送するルールを追加します
ステップ6:ローカルDNS用にリージョナルなS3アクセスを有効化
次のいずれかの方法で実現できます。
- インターネット接続用のInternet GatewayまたはNAT Gateway
- VPC AにS3 Gateway Endpointを配置する(コスト面で推奨)
- プライベートDNSを有効化したS3 VPC Interface EndpointをVPC Aに配置する
推奨は、S3にアクセスする必要があるVPC/リージョンごとにS3 Gateway Endpointを配置する方法です。他の選択肢と異なり、時間料金もトラフィック処理料金もかからないからです。
リージョン間S3アクセス向けのAWS SDK設定
オプション1:リージョナルエンドポイントを明示的に指定する
JavaScript SDK V2の例:

オプション2:リージョン間アクセスを有効化する
- **JavaScript SDK v3:**S3クライアントの設定で
followRegionRedirects: trueを指定します [8]
JavaScript SDK v3の例:

**注:**Java SDK V2では、別リージョンのバケットへの初回リクエストはレイテンシが大きくなる可能性がありますが、2回目以降はキャッシュされたリージョン情報により改善します。
一方、JavaScript SDK V3はリージョン情報をキャッシュしないため、これは当てはまりません。リージョン間リクエストのたびにリダイレクトのレイテンシが発生する可能性があります。リージョン間アクセスのパターンが事前に分かっている場合は、パフォーマンス向上のため、リージョナルエンドポイントURLを明示的に指定することを検討してください。
AWS CLIはこの種のリダイレクトを自動で処理してくれるため、上記のステップ6を済ませていれば、バケットごとにリージョンやエンドポイントURLを指定する必要はありません。
全体の動作フロー
- インスタンスはリージョナルなS3サービスに問い合わせ、バケットの所在リージョンを特定します
- バケットが
us-east-1にあると分かると、us-east-1でのIPをDNSに問い合わせます - Private Hosted ZoneがそのDNSクエリを横取りし、VPC B内のS3 Interface EndpointのプライベートIPに解決します
- S3 Interface EndpointのプライベートIPがEC2に返されます
- VPC A側のEC2サブネットのルートテーブルに追加したルールにより、そのプライベートIP宛のトラフィックはVPCピアリング接続を経由してVPC Bへ、さらにS3 VPC Interface Endpointへとルーティングされます
- エンドポイントが
us-east-1のS3バケットへセキュアでプライベートなアクセスを提供します
S3からのレスポンス(オブジェクトを取得した場合の応答など)は、VPCピアリング接続を逆向きに辿ってVPC AのEC2インスタンスへ戻ってきます。
アーキテクチャの概念図
このアプローチが有効な理由
- VPCピアリングを活用してリージョン間の接続性を確保
- プライベートPHZでのDNS解決により、適切なリージョナルS3エンドポイントのプライベートIPを取得
- インターネット経由ではなくVPCエンドポイントを使うことでセキュリティを担保
- クライアントアプリ側の変更は不要——アプリケーションに手を入れる必要はなく(リージョンやエンドポイントURLの指定も不要)、バケット名をそのまま使えます
押さえておきたいポイント
レイテンシへの影響:リージョン間トラフィックは同一リージョン内のアクセスよりレイテンシが大きくなります。パフォーマンスが重要な場合は、代わりにバケットレプリケーションの活用を検討してください[6]。
複雑さとのトレードオフ:この構成はアーキテクチャの複雑さを増します。得られるメリット(コストとVPC内のセキュリティ)が、追加の運用負荷に見合うかを見極めましょう。
コールトゥアクション
参考資料
- https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html#create-interface-endpoint-aws
- https://docs.aws.amazon.com/vpc/latest/peering/create-vpc-peering-connection.html
- https://aws.amazon.com/vpc/pricing/
- https://aws.amazon.com/privatelink/pricing/
- https://docs.aws.amazon.com/AmazonS3/latest/userguide/replication.html
- https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/s3-cross-region.html
- https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-middleware-sdk-s3/Interface/S3InputConfig/
- What is VPC Peering
- Gateway endpoints for Amazon S3
- Working with Private Hosted Zones
みなさんはご自身のAWS環境で、リージョン間のVPC接続をどのように実装していますか?経験談や、このアプローチを応用した工夫があれば、ぜひ教えてください。