AWS API Gateway VPCリンクでプライベートコンテナにインターネットからアクセスする

# 初めに

API Gateway のプライベート統合を利用して、ECS によりプライベートサブネットにデプロイされたアプリケーションにアクセスする方法について紹介します。プライベート統合は VPC 内のリソースに VPC 外からアクセスするための機能です。

> API Gateway のプライベートな統合により、VPC 内にある HTTP/HTTPS リソースを VPC 外のクライアントがアクセスできるように簡単に公開できます。プライベート VPC リソースへのアクセスを VPC 境界を超えて拡張するために、プライベート統合で API を作成できます。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-private-integration.html

プライベート統合を使用するために VPC リンクという機能を使います。

> VPC リンクを使用すると、Application Load Balancer または Amazon ECS コンテナベースのアプリケーションなどの、HTTP API ルートを VPC 内のプライベートリソースに接続するプライベート統合を作成できます。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/http-api-vpc-links.html

なお VPC リンクを使ったプライベート統合は、ALB のスキームに**内部向け**を選択しないとうまくいかないようです。最初、インターネット向けでやっていましたが、エラーレスポンスが返ってきました。

以下のチュートリアルの CloudFormation のテンプレートも内部向けになっていました。

```yaml
Scheme: internal
```

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/http-api-private-integration.html

# 手順

## 1. VPC リンクを作成

「HTTP API の VPC リンク」を選択し、アプリケーションをデプロイする VPC を選択します。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/4aae0993-005c-550d-f396-6522dc71cb6e.png)

サブネットとセキュリティグループを選択し、「作成」をクリックします。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/675165c4-080f-a835-375d-3194539037cf.png)

## 2. ALB を作成

スキームは「内部」を選択します。インターネット向け ALB を作成したところ、ブラウザに

> {"message": "Service Unavailable"}

と表示され、503 エラーが発生しました。ALB のトラフィックを確認したところ、リクエストが ALB まで到達していませんでした。VPC リンクを使ったプライベート統合は、内部向けしか選択できないようです。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/5cc70df9-3b36-098d-dd05-67a0610778c7.png)

VPC と プライベートサブネットを選択します。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/fb54f9d6-4cd6-8561-a383-4d196e9d78e2.png)

ターゲットグループを作成します。種類は IP を選択します。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/9bdce7b7-5720-7581-7de7-6f19aaa9aedc.png)

## 3. API Gateway の HTTP API を作成

HTTP API の「構築」をクリックします。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/97208908-74ad-212e-fec9-a01947fec8dc.png)

API 名を入力し、「次へ」をクリックします。

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/098dc7ac-19dc-a1b2-30d1-46ff4ff49a1b.png)

「次へ」をクリックします。

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/6e9740e1-ba0b-d953-d200-9d0ee27482d0.png)

「次へ」をクリックします。

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/76cb3de6-8628-994b-9b38-687cbb96b9c5.png)

「作成」をクリックします。

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/465be10f-38be-5975-c91a-fb45a90a09ac.png)

ルートを作成します。「Create」をクリックします。

![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/f0525ea0-8ec8-7aa7-a66e-c3592be09ccd.png)

パスには「/{proxy+}」と入力し、「作成」をクリックします。

![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/b275968a-b5b4-62b0-b109-0ef1f5088fff.png)

プライベート統合を作成します。「統合をアタッチする」をクリックします。

![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/a58195c8-e333-97b3-eede-96d72f9ad245.png)

「統合を作成してアタッチ」をクリックします。

![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/939f44da-80c7-a615-3cbb-8ec0041e54bd.png)

統合タイプは「プライベートリソース」を選択します。

![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/69b012af-6a25-8631-ccac-2712b415f202.png)

以下のように ALB とリスナーを選択します。

![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/e7549de0-5940-5e80-3393-fb859bc642d3.png)

VPC リンクを選択し、「作成」をクリックします。

![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/d388ae1f-cdba-2935-acbc-20ff529b49a9.png)

## 4. エンドポイントを作成

以下のエンドポイントを 4 つ作成します。**インターフェース型はすべてプライベート DNS 名を有効化**します。

![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/3a9d0f5c-3ef9-e66b-37a5-b8971252d834.png)

## 5. Fargate でアプリケーションをデプロイ

サービスを作成します。VPC とプライベートサブネット、セキュリティグループを選択します。パブリック IP の自動割り当ては「DISABLED」を選択します。

![19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/6314198a-cb9a-13a8-0ae6-db725222f97b.png)

ALB を選択します。後はデフォルトの設定で進めます。

![20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/63a5a304-a19d-1c19-91d6-a3f5c0b33606.png)

デプロイが完了しタスクが RUNNING になったら、API の呼び出し URL をブラウザに貼り付けます。

![21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/d9a5a696-9a23-fc1d-3da9-e388989e06c3.png)

インターネットからプライベートコンテナにアクセスできました。

![22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/aa5ae754-32ee-7182-dbb5-be6d37b36817.png)

# 注意

以下は検証していませんが、定期的にリクエストを送って防ぎたいです。

> VPC リンク経由で 60 日間トラフィックが送信されない場合は、INACTIVE になります。VPC リンクが INACTIVE 状態の場合、API Gateway は VPC リンクのネットワークインターフェイスをすべて削除します。これにより、VPC リンクに依存する API リクエストが失敗します。API リクエストが再開すると、API Gateway はネットワークインターフェイスを再プロビジョニングします。ネットワークインターフェイスを作成し、VPC リンクを再度アクティブ化するには、数分かかることがあります。VPC リンクステータスを使用して、VPC リンクの状態を監視できます。

# ALB のスキーム

インターネット向けと内部向けの違いについて簡単にまとめます。

## インターネット向け

- インターネット向けロードバランサーのノードにはパブリック IP アドレスが必要
- インターネット向けロードバランサーの DNS 名は、ノードのパブリック IP アドレスにパブリックに解決可能
- インターネット向けロードバランサーは、クライアントからインターネット経由でリクエストをルーティングする

## 内部向け

- 内部ロードバランサーのノードはプライベート IP アドレスのみを持つ
- 内部ロードバランサーの DNS 名は、ノードのプライベート IP アドレスにパブリックに解決可能
- 内部向けロードバランサーは、ロードバランサー用に VPC へのアクセス権を持つクライアントからのみ、リクエストをルーティングする

## 共通点

- インターネット向けロードバランサーと内部向けロードバランサーは、どちらもプライベート IP アドレスを使用してリクエストをターゲットにルーティングする

確かにパブリックサブネットでコンテナを起動したとき、ノードの IP アドレスがプライベート IP だったのが不思議でした。

# 参考記事

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-private-integration.html

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/http-api-private-integration.html

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/http-api-vpc-links.html

https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/userguide/how-elastic-load-balancing-works.html

https://forums.aws.amazon.com/thread.jspa?threadID=319735

https://stackoverflow.com/questions/61012712/amazon-http-api-gateway-not-working-via-vpc-link