REST APIをCloudFront経由のアクセスしか許可しないようにしてみる

# 概要

本記事は [AWSでWebアプリを構築してみる](https://qiita.com/ti_and6id/items/9670ee60965a4d10bec7) シリーズの6回目の記事です。
前回の記事は [こちら](https://qiita.com/ti_and6id/items/9670ee60965a4d10bec7)。

# 本記事で作成する構成

![AWS.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630916/a0be0370-b74b-e124-6949-8af33f18fb17.png)


図のようにCloudFrontを経由した間接的なアクセスのみ可能な状態で、API GatewayでのAPIに直接アクセスすることができなくなります。基本的には [静的ウェブサイトをCloudFront経由のアクセスしか許可しないようにする](https://qiita.com/ti_and6id/items/e9ef9da23b3e33116f6b) で行ったことと似ています。

# REST APIをCloudFront経由のアクセスしか許可しないようにしてみる

## 1. CloudFront にオリジンを追加する

1. マネジメントコンソールから CloudFront を開き、[静的ウェブサイトをCloudFront経由のアクセスしか許可しないようにする](https://qiita.com/ti_and6id/items/e9ef9da23b3e33116f6b) で作成したディストリビューションを開く

1. ディストリビューションのオリジンタブより「オリジンを作成」をクリック

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630916/f74b3f1b-bde9-6f38-0342-a01d3f5141ed.png)

1. Origin domain に [REST APIを作成してみる](https://qiita.com/ti_and6id/items/b5fd3eec7bf0a68ecc8c) で作成した API Gateway を選択して、オリジンを作成する

     ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630916/36369ec5-451f-68a4-d239-010a1361eb6c.png)

1. 「カスタムヘッダーを追加」でヘッダーを追加する

    カスタムヘッダーを追加するのはAPI GatewayへのアクセスをCloudFrontからのみに限定するしかけのためで、Referrerヘッダーに任意の値を設定する。
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630916/08b42b9e-6ad8-a677-e869-c5881518e693.png)

## 2. CloudFront にビヘイビアを追加する

1. ディストリビューションのビヘイビアタブより「ビヘイビアを作成」をクリック

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630916/7c28633b-68bb-c04f-0272-521e1b0f417f.png)

1. パスパターンを「/api/*」のようにし、オリジンとオリジングループで [REST APIを作成してみる](https://qiita.com/ti_and6id/items/b5fd3eec7bf0a68ecc8c) で作成した API Gateway を選択して、ビヘイビアを作成する

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630916/1928da26-dc0b-5404-dec0-96ca1c603014.png)

## 3. API Gateway のステージを変更する

1. マネジメントコンソールから API Gatewa を開き、[REST APIを作成してみる](https://qiita.com/ti_and6id/items/b5fd3eec7bf0a68ecc8c) で作成したAPIを開き、ステージを削除する

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630916/12e84b1e-b2a2-82d5-41cb-19c6b0afc852.png)


1. マネジメントコンソールから API Gateway を開き、[REST APIを作成してみる](https://qiita.com/ti_and6id/items/b5fd3eec7bf0a68ecc8c) で作成したAPIを開き、GETメソッドで「APIをデプロイ」をクリック

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630916/909c3eda-30a8-caa3-f952-e6c437e8a2e7.png)

1. サイドメニューのステージで「Create stage」をクリックし、ステージ名を「api」にしてデプロイする

    CloudFront のビヘイビアでパスパターンを「/api/*」のようにして、API Gateway にリクエストされるように設定したので、API Gateway 側でもステージ「api」を作成する。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630916/732f32c8-3957-874f-12fa-72d44ae8d296.png)

## 4. API GatewayへのアクセスをCloudFrontのみに限定する

1. サイドメニューのリソースポリシーで「ポリシーを作成」をクリックして、以下のようにリソースポリシーを設定する

    ```
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": "*",
                "Action": "execute-api:Invoke",
                "Resource": "arn:aws:execute-api:<リージョン>:<アカウントID>:<API ID>/*/*/*"
            },
            {
                "Effect": "Deny",
                "Principal": "*",
                "Action": "execute-api:Invoke",
                "Resource": "arn:aws:execute-api:<リージョン>:<アカウントID>:<API ID>/*/*/*",
                "Condition": {
                    "StringNotEquals": {
                        "aws:Referer": "<CloudFrontのオリジンドメインのカスタムヘッダー（Referrer）に設定した値>"
                    }
                }
            }
        ]
    }
    ```

1. サイドメニューのリソースで「APIをデプロイ」をクリックし、再デプロイして反映する

## 5. CloudFront経由でのAPI呼び出しをテストしてみる

1. マネジメントコンソールから CloudFront を開き、[静的ウェブサイトをCloudFront経由のアクセスしか許可しないようにする](https://qiita.com/ti_and6id/items/e9ef9da23b3e33116f6b) で作成したディストリビューションを開き、ディストリビューションドメイン名をコピーし、末尾に「/api/」を付加してブラウザで開く

    ↓以下のようなレスポンスがあればCloudFront経由でのAPI呼び出しに成功している
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630916/f334dba4-2f5f-00f3-d471-3e78729fd613.png)