Amazon API Gatewayで全部HTTPSでオンプレミスにつなげてみる

# はじめに

オンプレミスで稼働しているアプリケーションだけど、様々な外部システム連携のためのAPIゲートウェイを用意しよう、という場合に、AWSを利用していれば**Amazon API Gateway** (以下、API Gateway)が1つの選択肢として考えられますね。

例えばこんな感じの状況や背景でしょうか。

1. 基幹系システム自体への改修は最小限にしつつ、インターネットへの窓口(外接口)でAWSを利用している。
1. 現行システムになるべく手を加えずに、インターネットからの連携先システムからのAPI通信を受け付けて、オンプレミスシステムにつなげてみる。
1. 初期投資を極力抑え、スモールスタートしたい

どれも、またそれらの組み合わせはよくありそうな気がします。

### やりたいこと

こういった場合、やりたいことはシンプルに表現すると下図のようなイメージになります。

![Qita_000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919716/64ebd190-b091-1054-6b4b-950cbb10a0cd.png)

まだあくまでイメージです。

:::note info
API Gatewayは、どのAPIタイプであれ、必ずセキュア通信が前提となりますので、外部システムからAPI Gatewayまでは常にTLSによるセキュア通信となります。
:::

また、ここで外部システムに提供するAPIの種別としては、REST型で考えていくことにします。

### その上で例えばこんな要件があったとして…

セキュリティポリシーによっては、インターネットからAPI Gatewayまでの経路のみならず、API Gatewayから、AWS Direct Connectによる閉域ネットワークを介したオンプレミスシステム内のロードバランサーまでは、全部HTTPSで通信しなければならない、そうすべき、というお話があったとしたらどうでしょうか?

つまり全部HTTPSにするので、こんな感じです。


![Qiita_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919716/917d4f47-9e4d-8a01-13d5-7a5bb65ccee9.png)

さらに、ありそうなお話として、オンプレミス内では、それを理由に簡易的に自己署名証明書を使ってロードバランサーで待ち受ける際のHTTPS通信を実現させている、ということにしましょう。

ではこれを実際に実現するにはどうしていけば良いか、API Gatewayを起点に考えてみましょう。

#### 1. VPCリンクでユーザーVPCに接続する

API Gateway (ここではREST型 APIとします) のバックエンドとして、最終的にオンプレミスに到達させる場合は、ユーザーVPCを経由する必要があります。
API Gateway の REST APIをユーザーVPCに接続するためには、ユーザーVPCに **Network Load Balancer (NLB)** をポイントし、「VPCリンク」という定義を作成することで実現できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919716/8eda8b17-84f9-a1ac-03d4-2bb7a8f05bc8.png)


#### 2. エンドポイントURLを指定する

しかし、REST APIでバックエンドに指定する「バックエンドURL」には、何を設定すれば良いでしょうか?

非セキュアな、つまりHTTPの通信でよければ NLBに払い出されているホスト名(*.amazonaws.com)をそのまま指定すれば良いのですが、しかし今回は前提としてすべてHTTPSで通信する必要があります。

またこのとき、API Gateway自身がクライアントとなって HTTPSリクエストを送信することになることを押さえておく必要があります。そしてもう一つ重要な点として…

:::note warn
API GatewayがHTTPS通信可能な先は、自己署名証明書でホストされているエンドポイントには通信できない
:::

…という仕様上の前提があります。具体的には、以下のリンク先に記載のCAによって証明されたサーバー証明書でサービスがホストされている必要があります。


https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-supported-certificate-authorities-for-http-endpoints.html 


エンドポイントは httpsスキーム でなければなりません。となると、NLBに対してまずTLSでのリクエストを送信する必要があるわけですが、https://<IPアドレス> といったエンドポイントURLは指定できないことになります。

最終的にオンプレミスに対してHTTPS通信をしたい、と考えるとAPI Gateway自身がクライアントとして、その通信先に名前解決した先がNLBである必要があります。

さらに最終的な到達先であるオンプレミスのロードバランサーは自己署名証明書でホストされているので、直接的にAPI GatewayからみてのHTTPS通信先として指定することができません。

**ではどうすれば良いでしょうか?**

いくつか方法は考えられそうですが、ここはできるだけマネージドなサービスを活用することを念頭に、「NLBのバックエンドとして、ALBを指定できるようになった」という2021年9月のサービスアップデートを活用することにしましょう。

:::note info
それまでもNLBのバックエンドとしてALBを指定することはNLBのターゲットグループをLambda関数を利用してALBの現在のIPアドレスを動的に設定し維持し続ける、というテクニックを利用することで可能ではありましたが、このアップデートによってそういった考慮やユーザー側での対処が不要になりました。
:::


#### 3. 最終的な構成

ということで、最終的にはこのような構成であれば、問題なくオンプレミスのロードバランサーまですべてHTTPSでセキュアに通信ができることになりますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919716/b4b94d89-74f3-9dea-ebb9-4cfe80d03c32.png)

- オンプレミスのロードバランサーからみてクライアントとなるのは、ユーザーVPC内のALBとなります。ALBは、(API Gatewayと異なり) 自己署名証明書でホストされているサービスに対してもHTTPSで通信することができます。
- ALBには、AWS Certificate Managerを用いて、VPCリンクの通信先のNLBのホスト名でHTTPS通信を受け取ることができるようにHTTPSリスナーを構成します。
- API GatewayがVPCリンクの通信先のNLBに対して、HTTPS通信を送信するように、そのNLBへと名前解決されるRoute 53 Public Hosted Zoneのエイリアスレコードを追加します。


### まとめ

これで当初の目的の、すべての通信箇所がHTTPS、そしてオンプレミス上で用いている自己署名証明書であってもそれを許容する、という構成を実現できました。

似たような課題をお持ちの方にとって、何かのご参考なれば嬉しいです。