API Gateway(REST API) のアクセス元を CloudFront のみに許可するには

API Gateway のアクセス元を CloudFront のみに許可したい

Cloudfront の オリジンとして API Gateway を使用する構成において、API Gateway 側で CloudFront からのアクセスのみを許可したい場合に、どんな方法があるか調べてみた。

API Gateway(REST API) のアクセス元を CloudFront のみに許可する 2 つの方法

方法その 1: API Gateway の API キー認証を使う

API Gateway にて API の実行に API キーを必須に設定し、CloudFront のカスタムヘッダーとして API キーを送信するように設定することで、特定の CloudFront ディストリビューションからのアクセスのみ許可する方法となります。1

方法その 2: API Gateway のリソースポリシーと AWS:Referer を使う

API Gateway のリソースポリシーにて API の実行に AWS 値が特定の文字列であることを条件に設定し、CloudFront のカスタムヘッダーとして Referer リクエストヘッダーをオリジン(API Gateway)に送信するように設定することで、特定の CloudFront ディストリビューションからのアクセスのみ許可する方法となります。

API Gateway(REST API) のアクセス元を CloudFront のみに許可する 2 つの方法の留意点

方法その 1 (API Gateway の API キー認証を使う)の留意点

  • API キーは API Gateway のリソースとメソッドの組み合わせ毎に設定する必要があります。
    自分が調べた限り、現時点(2022/09)時点で全てのリソースとメソッドの組み合わせに一括で API キーを必須にすることはできません。
    そのため、リソースとメソッドの組み合わせが追加されるたびに、都度その  API キーの設定を有効にする必要があります。
  • 使用できない一例: API キーを複数発行し、顧客に配布し、顧客はその API キーを使って API を実行するといった API キー及び使用量プランの本来の使い方?をする場合

方法その 2 (API Gateway のリソースポリシーと AWS:Referer を使う)の留意点

  • API キー認証の時と違い、こちらの方法では、API 全体に対して制限をかけることが可能なため、リソースとメソッドの組み合わせが追加される度に設定を行う必要がありません。
    一方で、特定のリソースとメソッドの組み合わせに対してアクセス制限を適用したくないなどの場合は、リソースポリシーの変更が必要となります。
  • 使用できない一例: オリジンリクエストポリシーにて Referer リクエストヘッダーをオリジン(API Gateway)へ送信し、Lambda などのバックエンド側でクライアント側で設定された Referer リクエストヘッダーを参照する必要がある場合

事前準備

API Gateway の作成

API タイプは REST API で API Gateway を作成します。
リソース設定は、ルートパスに GET メソッドを作成します。
統合リクエストは、統合タイプとして [Mock] 選択して作成します。

リソース設定

API を任意のステージにデプロイします。
デプロイ後、 ステージエディター画面の上部にある Invoke URL(API Gateway API を呼び出すための URL) をメモしておきます。

API ステージ

ここまでの設定に問題がなければ API が実行できるはずです。
一旦、curl など API が 200 OK レスポンスを返すことを確認しておきます。

Copied!
$ curl -X GET -I  https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod
HTTP/2 200
date: Sun, 06 Mar 2022 02:39:23 GMT
content-type: application/json
content-length: 0
x-amzn-requestid: 46533423-7524-481e-9b47-9a48a83e9aa4
x-amz-apigw-id: OinCTHqDNjMFftQ=

CloudFront の作成とカスタムヘッダー(Referer)の設定

オリジンリクエストポリシーを作成後、CloudFront ウェブディストリビューションを作成します。
[オリジンドメイン]は API の invoke URL を指定します。
因みに、選択肢として invoke URL は表示されないので、直接入力する必要があります。

[オリジンパス]は省略可能です。
ここでは、API のステージ名(prod)を指定しています。
これは、API 呼び出し時にステージ名を指定したいか否かで変わります。
API を呼び出すときにステージ名を自分で入力する場合は、[オリジンパス]を入力する必要はありません。

CloudFront 作成 1
CloudFront 作成 2

API キーを使って API Gateway のアクセス元を CloudFront のみに許可する手順

API キー必須化

事前準備の API Gateway で作成した GET メソッドの[メソッドリクエスト]で [API キーの必要性] を true に設定し、API キーの使用を有効化しておきます。

API キー必須化

使用量プランの設定と API キーの作成

使用量プランを作成します。
スロットリング2とクォータ2それぞれの制限はデフォルトで有効化されていますが、顧客に API を公開して制限をかけるなどの要件がなく、特に制限する必要がなければ無効化することもできます。

使用量プラン作成

[API ステージの追加]ボタンをクリックして、API キーの作成と使用量プランへの紐付けを行います。

API キー追加後

設定完了後に作成した API キーの画面で [表示] をクリックして表示される API キー値をメモしておきます。

API キー確認

一旦ここで設定がうまくいっているか動作確認してみます。
まず、API キーをしているパターンを実行し、200 OK レスポンスを返すことを確認します。
API キーは HTTP ヘッダーに x-api-key というヘッダー名で付与します。

Copied!
$ curl -I -X GET  https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod -H 'x-api-key: <API キー値>'
HTTP/2 200
date: Sun, 06 Mar 2022 04:06:26 GMT
content-type: text/html
content-length: 1310
x-amzn-requestid: 27cf9c40-a378-48c4-aa42-a293ac5e5f99
x-amz-apigw-id: OizyaHnGNjMFSxQ=

因みに、x-api-key ヘッダーを付与していない場合、ステータスコードが 403ForbiddenException エラーを返します。

Copied!
$ curl -I -X GET  https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod
HTTP/2 403
date: Sun, 06 Mar 2022 04:06:24 GMT
content-type: application/json
content-length: 23
x-amzn-requestid: 7fca17f5-f15c-4c7b-98aa-a6e802f91ed4
x-amzn-errortype: ForbiddenException
x-amz-apigw-id: OizyLF_LtjMF30w=

CloudFront のカスタムヘッダー(x-api-key)の設定

[カスタムヘッダーを追加]で x-api-key というヘッダー名で API キー値を追加します。

x_api_key の設定

API キーの動作確認

動作確認してみます。
CloudFront の URL で API を呼び、200 OK レスポンスを返ってくれば成功です。

Copied!
$ curl -I -X GET  https://xxxxxxxxxxxxx.cloudfront.net -H 'x-api-key: <API キー値>'
HTTP/2 200
content-type: text/html
content-length: 1310
vary: Accept-Encoding
date: Sun, 06 Mar 2022 05:12:30 GMT
x-amzn-requestid: bd9d0322-ba24-44ed-9553-de4858ec9536
x-amz-apigw-id: Oi9duGUWtjMFm8g=
x-cache: Miss from cloudfront
via: 1.1 fcdc790e9970e122cf39adadda463c14.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT20-C4
x-amz-cf-id: 4z_1D1-ecgMQKc7plvtbL-c1e0Vx9dosRbklBpr3HRmWoqdGLoA1uw==

API Gateway のリソースポリシーと AWS を使って API Gateway のアクセス元を CloudFront のみに許可する手順

リソースポリシーの設定

API Gateway のリソースポリシーを以下のように設定します。
コンソール上から入力せいて保存すると Resouce の部分が自動的に以下のような arn に変換してくれます。
arn:aws:execute-api:<Region>:<AWS アカウント ID>:<API ID>/*

Copied!
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "execute-api:Invoke",
      "Resource": "execute-api:/*",
      "Condition": {
        "StringNotEquals": {
          "aws:Referer": "<適当な文字列>"
        }
      }
    },
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "execute-api:Invoke",
      "Resource": "execute-api:/*"
    }
  ]
}

一旦ここで設定がうまくいっているか動作確認してみます。
まず、Referer リクエストヘッダーを設定しているパターンを実行し、200 OK レスポンスを返すことを確認します。

Copied!
$ curl -I -X GET https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod -H 'referer: <リソースポリシーに設定した適当な文字列>'
HTTP/2 200
date: Tue, 20 Sep 2022 08:46:56 GMT
content-type: application/json
content-length: 0
x-amzn-requestid: 53309964-1549-48c9-8e5f-512a282f03a8
x-amz-apigw-id: YwCgFGHVtjMFieg=

因みに、Referer ヘッダーを付与していない場合、ステータスコードが 403 の ForbiddenException エラーを返します。

Copied!
$ curl -I -X GET https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod
HTTP/2 403
date: Tue, 20 Sep 2022 08:47:16 GMT
content-type: application/json
content-length: 182
x-amzn-requestid: 0e2809c8-2295-44f0-b3b5-6db8fdca4b1f
x-amzn-errortype: AccessDeniedException
x-amz-apigw-id: YwCjKF8jNjMFTfg=

CloudFront のカスタムヘッダー(Referer)の設定

[カスタムヘッダーを追加]で Referer というヘッダー名でリソースポリシーに設定した適当な文字列値を追加します。

refere の設定

なお、オリジンリクエストポリシーにて Referer リクエストヘッダーを設定している場合、以下のようなエラーが発生します。
The paramater Header Name with value Referer is not allowed as both as origin custom header and a forward header

refere の設定エラー

Referer の動作確認

動作確認してみます。
CloudFront の URL で API を呼び、200 OK レスポンスを返ってくれば成功です。

Copied!
$ curl -I -X GET https://xxxxxxxxxxxxx.cloudfront.net/
HTTP/2 200
content-type: application/json
content-length: 0
date: Tue, 20 Sep 2022 08:49:51 GMT
x-amzn-requestid: e4752a73-95b0-462a-b643-512198da6475
x-amz-apigw-id: YwC7dGMCNjMFS-w=
x-cache: Hit from cloudfront
via: 1.1 1ec5c4b165968f8e5c872b374a497e8e.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT57-P2
x-amz-cf-id: TjTMUnRNKNCro-IifX67z5YnW3L0CcinXiTr0UAEMt6FPhDWXpKU_Q==
age: 46

Footnotes

  1. カスタム CloudFront ディストリビューションで API Gateway をセットアップする

  2. API キーを使用した使用量プランの作成と使用 - Amazon API Gateway 2