VPC連携なしで繋げられるプライベートなAPI連携を実装してみた（GoogleCloud編 + AWS編）

## はじめに
こんにちは！
ディップ株式会社 AI・DX事業本部でクラウド・インフラの担当している藤井です。
aws で稼働するプロダクト と Google Cloud で稼働するプロダクトを担当しており、マルチクラウド・インフラエンジニアとして、設計から運用までを担当しています。

この記事はディップ Advent Calendar 2022 の22日目の投稿です。

## TL;DR
異なるVPC、異なるプロジェクト／アカウント間でプライベートなAPI連携を実装したい場合、Google Cloud（GCP）とAWSには 「VPC連携なしで繋げられるプライベートな接続」を実現する仕組みが提供されています。

GCP・AWS それぞれで実現できる仕組みの名称
- GCP：Private Service Connect
- AWS：PrivateLink

組織内だけに共通利用できるAPIを公開されたユースケースでも、「利用者側が申請して、提供側が許可する」といった仕組みがあるので、安心して提供できます。

もし該当する要件に出会った場合は、ぜひ採用を検討してみてください。

## アジェンダ
1. VPC連携なしでプライベートなAPI連携を検討したきっかけ
2. Google Cloudでやってみよう「Private Service Connect」
3. AWSでもやってもよう「PrivateLink」
4. まとめ

### 1. VPC連携なしのプライベートなAPI連携を検討したきっかけ

#### 「VPCピアリングができない！」どうしよう・・・

GCPで稼働するプロダクトのDBリプレイスがきっかけでした。
このプロダクトで、サブシステム間の直接DB参照をしている機能がありました。

将来的にDBのリプレイスを検討しており、リプレイス時には直接DB参照しているこの機能も変更する必要がありました。そこでリプレイス時の影響範囲を少しでも小さくするために、事前に「DB直接参照」から「API連携」へ変更し疎結合化することになりました。

#### 機能の概要
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120824/26f7d5b3-65ac-6282-aa9f-8486a8355e0b.png)

- DBはCloudSQL、処理Aの実行環境にはCloudRunを使用
- DBとCloudRunは、別々のGCPプロジェクトで構成
- CloudRunからDBへの接続には、CloudSQL Auth Proxyを使った直接DB参照をしていた


#### VPCピアリングできない！設計で困った問題
このAPI連携ではインターネット経由での接続にする必要はないので、セキュリティ面を考えるとプライベートな接続で実装する方針でした。
VPCをまたがったプライベートな接続を実現する手軽な方法として、「VPCピアリング」が思いつくと思います。
ところがこの環境は特殊なVPC構成になっていて、VPCピアリングをしようとすると「IPアドレスが重複していてピアリングが設定出来ない」という問題が発覚しました。
（そんな設計をしているの悪いというご意見があるのは重々承知しておりますが、ここでは割愛とさせてください）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120824/53c82c31-c42c-00a5-3988-ce2a32eb2f86.png)


#### VPCピアリングをしなくてよい回避策を考えよう 
他に簡単に実装できる方法を検討しました。

- インターネット経由で連携させる
  一度インターネットに出て、呼び出し側のアウトバンドのIPアドレス（CloudNATのIP）だけに接続を制限する方法です。確かにこの方法でも実現できますが、やはりセキュリティ的な観点からできれば避けたいと思いました。
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120824/9e67e23a-2b2a-62bd-2aa6-0f9d2c1450a3.png)

他にも方法がないか探しているうちに、「Private Service Connect」にたどり着きました。

#### Private Service Connect で実現するプライベートな接続 とは？

GCP 公式ドキュメント にかかれている Private Service Connect の 説明 です。
（[GoogleCloud ドキュメント](https://cloud.google.com/vpc/docs/private-service-connect?hl=ja)より）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120824/808353ac-e816-64cf-30e8-1c9e8a4be121.png)


> Private Service Connect は Google Cloud ネットワーキング機能の一つで、コンシューマーが VPC ネットワーク内からマネージド サービスにプライベート接続でアクセスできるようにします。

> Private Service Connect を使用すると、コンシューマーは VPC ネットワークから離れることなく、独自の内部 IP アドレスを使用してサービスにアクセスできます。トラフィックが Google Cloud の外に出ることはありません。


Private Service Connect で対応している接続パターンは３種類ありますが、今回は「組織内の公開サービス」のパターンに適合します。

> - Google の公開サービス（Apigee や GKE コントロール プレーンなど）
> - Private Service Connect パートナーが提供するサードパーティの公開サービス
> - 組織内の公開サービス。コンシューマーとプロデューサーが同じ企業内の 2 つの異なる VPC ネットワークとなる場合があります。


#### Private Service Connect を使った 組織内の公開サービス の 特徴

イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120824/8326bf4d-1e98-3c3a-fc94-7367af4b678f.png)

- 作成したAPIを公開して、プライベートな接続で接続できる
  - VPC同士を直接接続させる必要がない（VPCピアリング、VPN 等が不要）
    - 直接接続しないので、IPアドレスの重複も気にする必要がない
   - 異なるGCPプロジェクトでも連携できる
- 許可制になっているので、公開側で「接続元に接続を許可する・許可しない」を制御できる


## 2. Google Cloudでやってみよう「Private Service Connect」

### 構成図
簡易的なイメージですが、以下のように構成することで、「VPC連携無しでプライベートなAPI連携」を実現することができました。
公開サービス側には、Private Service Connect専用のロードバランサーが必要になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120824/6af82282-2dbc-f8b3-d40f-d56b66f0a378.png)

### Private Service Connect の設定画面イメージ

- APIを利用する側の設定画面（サブシステム A の エンドポイント）
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120824/99f064fb-356f-c3f5-9a1d-f4e6c2faf745.png)
  利用する側のエンドポイントでは、エンドポイントが所属するVPCのIPアドレスが割り当てられます。そのIPアドレスを指定することで、公開サービスのAPIを呼び出す事ができます

- APIを公開する側の設定画面（サブシステム B の 公開サービス）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120824/2a0bf3af-574b-ccd8-58cd-07ff2ec8c428.png)
  公開サービスでは、利用する側から申請されたものを、承認、または 拒否することが出来ます。仮に第三者が「サービスの接続」の文字列を知ることができたとしても、接続元を確認することでブロックすることが可能です。

Private Service Connectを使うことで、IPアドレスが重複してしまったVPCを直接連携させることなく、無事セキュアなAPI連携を実装し本番リリースすることができました。

## 3. AWSでもやってみよう「PrivateLink」

GCPでPrivate Service Connectを使った接続を稼働させた後、AWSを利用している別プロダクトでもVPCをまたがったAPI連携の話がでてきました。

AWSでも、VPC同士の連携による制約、インターネット経由にしたAPI連携のセキュリティ面の懸念は同じです。
AWSにも同じ要件を実現できる機能があるはずと思って、調査をしてみました。

調べたところ、「PrivateLink」で実現出来ることが分かりました。
PrivateLinkはAWSのサービス同士をプライベートに接続させる目的で構築したことがあったのですが、ユーザー側で構築したAPIにも適用できるとは知りませんでした。

#### PrivateLink で実現するプライベートな接続

AWS 公式ドキュメント にかかれている PrivateLink の 説明 です。
（[AWS ドキュメント](https://docs.aws.amazon.com/ja_jp/vpc/latest/privatelink/privatelink-share-your-services.html)より）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120824/54d095ac-a34a-4c15-0ba7-5d4274343959.png)

> AWS PrivateLink を使用して、サービスが VPC で直接ホストされているかのように、VPC 内のリソースがプライベート IP アドレスを使用して他の VPC 内のサービスに接続することを許可します。

> エンドポイントサービスと呼ばれる独自の AWS PrivateLink 搭載サービスをホストし、他の AWS のお客様と共有できます。

説明を見ると、GCP の Private Service Connect と同じことが実現できそうです。

### PrivateLink サービスの共有 の 特徴

イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120824/4d6f428d-1230-d00d-7637-f44d87aeded4.png)

「PrivateLink」は概念のことで、実際に利用する機能名は「VPCエンドポイント」になります。NLB構築し、VPCエンドポイントサービスを構築していきます。
API連携の要件で比較した場合では、GCPと同じことが実現できます。

- 作成したAPIを公開して、プライベートな接続で接続できる
  - VPC同士を接続させる必要がない（VPCピアリング、VPN 等が不要）
    - 直接接続しないので、IPアドレスの重複も気にする必要がない
   - 別のAWSアカウントでも連携できる
- 許可制になっているので、公開側で「接続元に接続を許可する・許可しない」を制御できる


### VPCエンドポイント の設定画面イメージ

本記事の作成時点では、まだ実際に本番稼働させるまで進捗していません。
検証ベースでの話になりますが、接続が出来ることまでは確認出来ています。

こちらもVPCエンドポイントの設定画面を共有します。

- APIを利用する側の設定画面（アカウントBB の VPCエンドポイント）
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120824/a74e782c-f2fc-2cea-088c-3bbce39f897d.png)
  GCPと同じで、所属するVPCのIPアドレスが割り当てられます。そのIPアドレスを指定すれば、公開サービスのAPIを呼び出す事ができます。  

- APIを公開する側の設定画面（アカウントAA の VPCエンドポイントサービス）
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120824/4dafe628-d2b3-3e5f-5db9-ce1e1d34dd6a.png)
  こちらもGCPと同じく、AWSアカウント（所有者）をみて、承諾するか却下するかを選ぶことができます。  

# 4. まとめ
今回は、IPアドレスが重複しているVPC間でどうAPI連携させるか？ からスタートしましたが、重複しない場合でも十分活用できるアーキテクチャーだと感じています。
この仕組みも万能ではなく、VPC間で多くのAPI連携が発生する場合には、VPCピアリング 等 VPC単位で直接連携させる仕組みの方が適切な場合もあると思います。

今回は Private Service Connect と PrivateLink を採用しましたが、他の実現方法もあるようなので、また学んでいこうと思います。

最後まで読んでいただきありがとうございました🙇‍♂️