
カミナシの「カミナシ 設備保全」チームでプレイングマネージャー型のエンジニアリングマネージャーをしてます、すずけん(@szk3)です。
先日、社内プロダクトの連携機能を実装するにあたり、カミナシの別サービスから自チームが管理するサービスのプライベートなAPIを呼び出す必要があり、サービス間API呼び出し経路について、CloudFrontの機能のひとつであるVPCオリジンを使って実装しました。
本エントリでは、VPCオリジンを導入する過程で得たVPCオリジンについての知見や、その判断に至るまでの背景をシェアします。
プライベートサブネットのAPIを呼び出したいニーズ増えてない?
昨今のAI/LLMアプリ開発の隆盛もあり、mcpサーバーからプロダクトのAPIを呼び出したり、自社・他社問わずサービス間連携したいというようなカジュアルなニーズも増えたように感じます。
一方で、実装する側の視点で言うと、要求としてはシンプルに『他プロダクト(やサービス)から、自プロダクトのAPIを呼び出したい』というだけに見えますが、実際にはプロダクトのAPIは大抵プライベートサブネットに配置されていたり、サービスごとにホスティングされているAWSアカウントが異なったりもします。
つまり、ただAPIを呼び出すだけと言うものの、プライベートサブネットに配置されているAPIにアクセスする為には、セキュリティと通信経路の両立に対して検討が必要であり考慮すべきことは多々あります。

プライベートサブネットのAPIへアクセスする為の設計アプローチ
プライベートなサブネットのリソースにアクセス方法はいくつかありますが、今回はアクセス元が他AWSアカウントにホスティングされているサービスだった為、AWSアカウント間連携によるアプローチ、もしくはインターネット経由によるアクセスでのアプローチにするか?が、設計方針を変えるひとつのポイントになりそうだと考えました。
そこで、この要件に対して、メンテナンスコスト、スケーラビリティ、インターネット経由の有無、という観点で、以下の5つのアプローチを比較しました。(他にもアプローチがあるとは思いますが今回は以下の案で検討しました🙏)
1. PrivateLink
VPC間をプライベート接続する標準的なソリューションで、最初に頭に浮かんだのはこの案です。悪くない選択肢だとは思いますが、プロダクト間連携の拡張性を考えると躊躇しました。
接続には、NLBを用意するパターンとResource gateway を用意するパターンがありますが、どちらにしてもアクセス元が増えるたびに設定変更が必要になり、運用コストが気になります。
メリット
- インターネットを経由しない
- 低レイテンシ
デメリット
- 新規プロダクトとの連携が増えるたびに、AWSアカウント間の設定が必要

2. VPC Peering
次に、VPC Peeringです。構成としてはシンプルですが、CIDRの制約が将来の運用・設計コストに与える影響を考えると、採用するには至りません。
メリット
- VPCからのアクセスに限定するシンプルな構成
- インターネットを経由しない
デメリット
- VPCのCIDR(IPアドレス範囲)が被ってはいけない制約を考慮しつづける必要がある
- 将来プロダクトが増えるたびに、新しいPeering接続が必要

3. AWS Transit Gateway
AWS Transit Gatewayは、多くのVPCと接続するような大量のアタッチメントを作成できます。ですが、いまのプロダクト規模では、明らかにToo muchな選択であり現状のコンテキストにはフィットしない為、深い検討はしていません。
メリット
- 多彩かつ大量の接続パターンを実現できる
デメリット
- 設定が複雑
- メンテナンスコストが高い
4. Public サブネットにALBを配置する
次にAWS間での疎通パターン以外にインターネット経由となると、publicサブネットにALBパターンがシンプルでよさそうに思います。ですが、これは現状の構成上パブリックサブネットにリソースを増やすことになります。
お手軽ではありますが、可能な限りパブリックサブネットにリソースを配置したくないという考えがある為、このパターンは採用しづらいです。また、APIをターゲットとしたALBがパブリック・プライベートのサブネットに2つ存在するのは若干複雑な(なんかイヤ)感じがします(主観です)
メリット
- リソース一個追加するだけでいいので簡単
デメリット
- パブリックサブネットにリソースを増やしたくない
- CloudFrontを通してパスルールを変えるので、内部からと外部からでAPIにアクセスするパスが変わる
- CloudFront経由しないならNLB+EIPの構成になりそれはそれでリソース増える

5. CloudFront VPCオリジン
最後にCloudFront VPCオリジンですが、こちらは比較的新しい機能なので馴染みが薄いかもしれません。CloudFront VPCオリジンは、プライベートサブネット内のALBやNLBをCloud Front のオリジンとして設定することができます。つまり、インターネット経路で、簡単にプライベートサブネットのAPIのALBを外部公開することが可能になるということです。
Amazon CloudFront VPC オリジンの紹介: アプリケーションのセキュリティ強化と運用の合理化 | Amazon Web Services ブログ
この案は、構成がめちゃくちゃシンプルになのにもかかわらず、運用コストも低い上に、他の案よりもスケーラビリティが圧倒的に優れている為、こちらの案を採用しました。
メリット
- 既存環境にCloudFrontを追加するだけ(新規コンポーネント最小限)
- VPCオリジン自体の利用は追加費用なし(CloudFront自体と、オリジンへの接続には費用がかかります)
- 接続元がAWSアカウントからのアクセスであることを考慮する必要がない
デメリット
- インターネット経由でのアクセスの為、攻撃のリスクが増える

では、次のセクションでもう少し詳しく見ていきます。
なぜVPCオリジンが適切なのか?
セキュリティ
プライベートなリソースへのアクセスを考えると、「インターネット経由 = 危険」という漠然とした不安が生じやすいものです。しかし、適切なセキュリティ対策を組み合わせることで、インターネット経由でも安全に公開できます。具体的には、CloudFrontの前段にWAFを配置してマルウェアやDDoS攻撃を検知・ブロックし、APIの認可層でアクセス権を厳密に制御することで、リスクを大幅に軽減できます。
CloudFront VPCオリジンを使うメリットのひとつとして、プライベートなリソースへのIngressポイントがCloudFrontになることで、必ずWAFを通すような通信経路にすることができることです。
従来の設計においては、VPCオリジンを使わずとも、オリジンアクセスを防ぐために ALB で CloudFront のマネージドプレフィックスリストや CloudFront でカスタムヘッダを付与しそれを ALB で検証することでセキュリティを高めることもできましたが、それでもWAFをバイパスされてしまう可能性を残してしまいます。WAF にいくら屈強なルールを仕込んでいたとしてもバイパスされてしまうのであれば意味がなく、その可能性をVPCオリジンを使うことで排除することができます。
WAFのバイパスについては、以前弊社セキュリティチームのnishikawaが書いたエントリに詳しく述べられていますので、ご参照ください。
kaminashi-developer.hatenablog.jp
また、VPCオリジンを作成すると同時にセキュリティグループ(CloudFront-VPCOrigins-Service-SG)が作成されます。APIの前段のALBのセキュリティグループで、インバウンドルールにCloudFront-VPCOrigins-Service-SGからのアクセスを許可するルールを追加することで、ALBのSGでもアクセス元を制限することができます。

運用効率
今回は、連携機能の開発対象が一つのプロダクトでしたが、もし仮に社内の全プロダクトから、プライベートサブネット上にあるAPIを呼び出したいとなった場合を想像するとどうでしょうか?
VPCオリジン以外の案では、AWS内の閉じた閉域網での通信というメリットがありますが、インフラ運用観点に置いては都度何かネットワーク構成の考慮・場合によっては変更が必要になってきます。しかし、VPCオリジンの場合は一度構築してしまえば、連携先が増えても特に何もする必要がありません。
また、API側の実装も、AccessTokenをintrospectionする際に検証ルールを少し書き換えるだけで済むので、運用コストが低い状態を維持できます。
この構成を取ることで、心理的負荷が高くなりがちなネットワーク構成の変更が不要な状態になり、マルチプロダクト間の連携コストを下げることができます。
実装時の工夫
gRPCプロトコルの対応
自チームのAPIは、Connect RPCで実装されており、当初ALBからターゲット(APIサービス)への通信は、gRPCプロトコルで行っていました。
ですが、CloudFrontはHTTPで通信する為、そのままだとプロトコルバージョンの不一致(HTTP STATUS 464エラー、Incompatible Protocol)が発生します。
そのため、API用のALBに プロトコルバージョンがHTTP/1.1の新しいTarget Group作成し、リスナールールのdefault に設定することで、通信プロトコルを変更しました。
プロトコルバージョンをgRPCとするTarget Groupは、リスナールールに残してあり、特定のヘッダーが付与されたときのみ、プロトコルバージョンがgRPCのターゲットグループを利用するような形にしてあります。
内部ALBに向けていたAPIサービスのドメイン名を、外部公開するCloudFrontでも使う
既存の構成では、APIサービス前段のALBに対してAPI用サブドメインを設定し、他のAWSリソースから利用していました。
しかし、今回の変更において、同じAPI用のサブドメインをCloudFront側でも利用したいと考えていました。
つまり、同じドメイン名を使う為に、外部公開用の名前解決と、内部公開用(AWS VPC内)での名前解決では別のIPを返す必要があります。
そのため、今回はRoute53にプライベートホステッドゾーンを追加し、外部に公開されているドメイン管理と分離することで、同じドメインで呼び出せるようにしました。
まとめ
CloudFront VPCオリジンは、運用負荷を抑え、スケーラビリティを落とさずに、セキュアに内部リソースを公開するのにとても便利な機能になっています。
もちろん設計はケースバイケースではあり、VPCオリジンが全ての設計パターンでハマることはないですが、今回のようなAWSアカウントを跨いだ複数プロダクト間のAPI連携を簡単に実現したいというカジュアルなニーズに対して工数もそこまでかからずにフィットします。
また、インターネット越しのアクセスを実現しているので、他のサービスとの連携もCloudFront VPCオリジンとAPIリソースでの適切な認可さえ実装していれば、プライベートなAPIであっても比較的安全に公開することが可能です。
設計のアイデアとして頭の片隅にストックしておくとどこかで役に立つかも知れません、機会があればぜひ一度検討してみてください。