話題の記事

[新機能] Amazon API GatewayプライベートAPIとVPCエンドポイントでプライベートなサーバーレスアプリ構築

Amazon API GatewayプライベートAPIとVPCエンドポイントを利用して、VPCやDirect Connectにサーバーレスアプリを提供する様子をご紹介します。
2018.06.17

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。
昨日、API Gatewayの新機能としてプライベートAPIがリリースされ、同時にAPI GatewayがVPCエンドポイントに対応しました。

API Gatewayは、AWS Lambdaとの組み合わせでAWSにおけるサーバーレスアプリケーションを実現する鉄板構成です。今回追加された2つの機能で、VPCやDirect Connectなどのプライベートなネットワークからのみアクセスできるプライベートなサーバーレスアプリを構築できるようになりました。その様子をご紹介します。

プライベートなサーバーレスアプリの構成

VPCエンドポイントは、AWSでプライベートなネットワークを提供するVPCからインターネットを経由せずにAWSサービスにアクセスできる機能です。最近対応サービスが増えてきており、今回VPCエンドポイント経由でAPI Gatewayにもアクセスできるようになりました。

一方でAPI Gatewayはこれまでインターネットからのアクセスのみを想定し、リージョンごとにエンドポイントを持つ地域タイプとエッジロケーションを利用するエッジ最適化タイプから選択していました。今回、リージョンごとにVPCエンドポイントを経由するアクセスのみ可能となるプライベートタイプが追加されたわけです。

プライベートタイプは一部 *1を除くAPI Gatewayのほとんどの機能が利用できるため、バックエンドにLambdaを構成することでVPCエンドポイント経由でプライベートネットワークにサーバーレスアプリケーションを提供できます。

1. VPCエンドポイントの作成

今回はAPI GatewayのサンプルAPI PetStoreをVPCからアクセスできるように、東京リージョンで構成してみます。

VPCやDirect ConnectからアクセスするためのVPCエンドポイントの作成をVPC管理画面のメニュー[エンドポイント] - [エンドポイントの作成]から行います。[サービスカテゴリ]は「AWSサービス」のままにし、サービス一覧からAPI Gateway(com.amazonaws.<リージョン名>.execute-api)を選択します。

加えてVPCサブネット(基本的には全部選択)およびセキュリティグループ(API GatewayはHTTPS:443なのでそれを許可するルール)を選択、エンドポイントを作成します。

エンドポイント一覧には、プライベートネットワークから接続するためDNS名がいくつか表示されます。それぞれ解説します。

  1. execute-api.<リージョン名>.amazonaws.com : ドキュメントにあるプライベートDNS名のひとつ。任意のAPI Gatewayにアクセスできるが証明書のCNが合わないため実用的ではなく、後述のCNAMEの振り先と推測される。Direct Connect経由のオンプレミスからは直接引けない点に注意。
  2. *.execute-api.<リージョン名>.amazonaws.com : ドキュメントにあるプライベートDNS名のひとつ。後の手順で作成するAPI Gatewayのリソース名をサブドメインに指定してアクセスする。Direct Connect経由のオンプレミスからは直接引けない点に注意。
  3. vpce-XXXX-XXXX.execute-api.<リージョン名>.vpce.amazonaws.com : ドキュメントにあるパブリックDNS名のひとつ。Hostヘッダに2のドメインを指定しないと動作しないため、あまり実用的では無い。
  4. vpce-XXXX-XXXX-<AZ名>.execute-api.<リージョン名>.vpce.amazonaws.com : ドキュメントにあるパブリックDNS名のひとつ。3と同様あまり実用的では無い。

というわけで、特別な事情がない限り2を常用することになると思います。

2. APIの作成

続いてAPI GatewayでAPIを管理画面の[APIの作成]から行います。今回は[APIの例]でサンプルのPetStoreをインポートしつつ、[名前と説明]の[エンドポイントタイプ]で「プライベート」を選択します。

APIを作成したら、画面上部のパンくずリストからAPIのリソースID(PetStore(XXXXXX)XXXXXX)を確認します。これがアクセスするリソースURLのサブドメインになります。

続いて画面左のメニューから[API] - [PetStore] - [リソースポリシー]を選択し、画面右下にある[ソースVPCホワイトリスト]ボタンをクリックしてリソースポリシーのテンプレートを呼び出します。

以下のJSONドキュメントがテキストエリアに貼り付けられるので、13行目の値を作成したVPCエンドポイントのIDに書き換えて[保存]をクリックします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": [
                "execute-api:/*"
            ],
            "Condition" : {
                "StringEquals": {
                    "aws:sourceVpce": "vpce-XXXXXXXXXXXX"
                }
            }
        }
    ]
}

画面左のメニューから[API] - [PetStore] - [リソース]を選択し、[アクション]ボタンをクリックし[APIのデプロイ]を選択します。[デプロイされるステージ]は[新しいステージ]で任意のステージ名(今回はv1)としてデプロイすればOKです。

動作確認

早速VPCに配置したEC2からアクセスしてみると...

$ curl https://XXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/v1/pets/
[
  {
    "id": 1,
    "type": "dog",
    "price": 249.99
  },
  {
    "id": 2,
    "type": "cat",
    "price": 124.99
  },
  {
    "id": 3,
    "type": "fish",
    "price": 0.99
  }
]$

正常にレスポンスが返ってきました。ホスト名のIPアドレスを調べてみると...

$ host XXXXXXXX.execute-api.ap-northeast-1.amazonaws.com
XXXXXXXX.execute-api.ap-northeast-1.amazonaws.com is an alias for execute-api.ap-northeast-1.amazonaws.com.
execute-api.ap-northeast-1.amazonaws.com has address 172.31.17.157
execute-api.ap-northeast-1.amazonaws.com has address 172.31.45.78
execute-api.ap-northeast-1.amazonaws.com has address 172.31.12.159

CNAMEになっていて、IPアドレスはVPCエンドポイントで設定したVPCサブネットのプライベートIPが返ってきています。VPC内で通信が完結していることがわかりますね。ちなみにサブドメインに何を指定してもexecute-api.ap-northeast-1.amazonaws.comが返ってくるので、Amazon DNS側ではCNAMEレコードがワイルドカードとして設定されているっぽいです。

$ host mesoko.execute-api.ap-northeast-1.amazonaws.com
mesoko.execute-api.ap-northeast-1.amazonaws.com is an alias for execute-api.ap-northeast-1.amazonaws.com.
execute-api.ap-northeast-1.amazonaws.com has address 172.31.12.159
execute-api.ap-northeast-1.amazonaws.com has address 172.31.17.157
execute-api.ap-northeast-1.amazonaws.com has address 172.31.45.78
$ host satoshi.execute-api.ap-northeast-1.amazonaws.com
satoshi.execute-api.ap-northeast-1.amazonaws.com is an alias for execute-api.ap-northeast-1.amazonaws.com.
execute-api.ap-northeast-1.amazonaws.com has address 172.31.45.78
execute-api.ap-northeast-1.amazonaws.com has address 172.31.12.159
execute-api.ap-northeast-1.amazonaws.com has address 172.31.17.157
$

言い換えると、VPCエンドポイントを一回作成しておけばそこから複数のプライベートAPIにアクセスできます。

まとめ

API GatewayプライベートAPIとVPCエンドポイントを利用して、サーバーレスアプリをプライベートサービスとして構築する様子をご紹介しました。Internal ELBのようにサーバーレスで開発するマイクロサービスを内部同士で呼び出すケースなどに利用できそうですね。

考察

興味深いのは、VPCエンドポイント側にはAPI GatewayのAPIを特定する設定を特に持たないところです。それゆえ任意のAWSアカウントのAPIにVPCエンドポイント経由でアクセスできるので、API Gatewayのリソースポリシーできちんと制限しないといけないわけですが、この特徴を逆手に取るとクロスアカウントでAPIを提供する手段としてオープンなプライベートAPIを作成することも可能だったりします。以下のリソースポリシーを試してみたところ、別のAWSアカウントのVPCエンドポイントでプライベートAPIにアクセスすることができました。動作確認用途のポリシーなので、十分リスクを理解したうえで利用してください

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": [
                "execute-api:/*"
            ]
        }
    ]
}

同様の機能で承認プロセスを踏むエンドポイントサービスもありますが、あちらよりも簡単に提供する手段として利用できるかもしれません。API Gatewayのカスタム認証APIキーを用いてアクセス元を識別する感じにすると良さそうですよね。

また、インターネットに出ない経路なので各種閉域サービスとの組み合わせも模索したいですね。VPCエンドポイントの制約でAWSハードウェアVPNは利用できない一方、Direct Connectを利用する各種閉域接続サービスでの利用を検討する価値がありそうです。IoT向け閉域サービスのSORACOM Canalのピア元(Virtual Private Gatewayのある)VPCでAPI Gateway用のVPCエンドポイントを用意してエンドポイントIDをユーザーに提示してくれると、IoTデバイスにプライベートAPI経由でサーバーレスアプリケーションを提供できて便利そうです。ソラコムさん、ご検討ください!

参考URL

脚注

  1. 2018年6月現在、プライベートタイプはカスタムドメイン名に非対応です。