こんにちは、野球と LoL(League of Legends) がシーズンオフとなり、心もシーズンオフの末廣です。
本ブログは、 Lambda プロキシ統合について理解した上で、Lambda 統合された API Gateway での CORS 設定を行っていくものとなります。CORS の基礎から設定方法、その具体例を用いて Lambda プロキシ統合について理解を始める参考にしてください。
※ 本ブログで使用する API Gatewayは HTTP API ではなく、REST API になります。
- CORS について
- Lambda プロキシ統合について
- Lambda プロキシ統合と CORS の関係と影響
- 実際の設定例
- API Gateway からのレスポンス形式
- API Gateway のCORS 設定方法まとめ
- おまけ:HTTP API の CORS 設定
- 最後に
CORS について
そもそも、CORS(Cross-Origin Resource Sharing)とはどういうものか、以下 Mozilla のドキュメントより引用です。
オリジン間リソース共有 (Cross-Origin Resource Sharing, CORS) は、追加の HTTP ヘッダーを使用して、あるオリジンで動作しているウェブアプリケーションに、異なるオリジンにある選択されたリソースへのアクセス権を与えるようブラウザーに指示するための仕組みです。 引用:オリジン間リソース共有 (CORS)
ちなみに「CORS」の読みですが、「コース」「コルス」「コウス」などそれぞれ…、 略称なので「クロスオリジン」とかでも良いでしょうか…
ドキュメント先に図もありますが、今回検証している AWS 環境での例を示してみます。
S3 をウェブサイトホスティングとし、S3 の Web ページ(アプリケーション)から異なるオリジンの API Gateway へ fetch などで API アクセスできるようにする仕組みが CORS になります。
この場合、CORS が有効化された通信の流れは以下のようになります。
- S3 Bucket (
http://xxx.s3-website-ap-northeast-1.amazonaws.com/index.html
)へリクエストを送信 - API リクエスト付きのファイルレスポンスを受信
- オリジンヘッダ(
http://xxx.s3-website-ap-northeast-1.amazonaws.com
)を付与したリクエストを API Gateway(https://xxx.execute-api.ap-northeast-1.amazonaws.com/default/
)へ送信 - CORS ヘッダ (
Access-Control-Allow-Origin
ヘッダ)に 3. で付与されているオリジンヘッダが含まれているレスポンスを受信
※ 4 のレスポンスの CORS ヘッダに 3 のオリジンヘッダが含まれていない、または CORS ヘッダがない場合 CORS 要求がブロックされます。
通信の流れ 3 、4 の間にて API Gateway と Lambda でサーバ側の処理が行われています。 ここで Lambda プロキシ統合が有効化されているかによって、オリジンヘッダを設定する方法が変わってくるのが本ブログの CORS 設定についての主題となります。
Lambda プロキシ統合について
Lambda プロキシ統合は、API Gateway で API メソッド を Lambda 関数に統合させる時に選択できるオプションです。
この設定を行うと、API Gateway はクライアントからの受信リクエストをイベントオブジェクトとして Lambda 関数に直接渡すようになります。また、Lambda からのレスポンスを API レスポンスとしてクライアントに返すには、Lambda 関数は結果を一定の形式で返す必要があります。
逆にプロキシ統合を行わない場合(非プロキシ統合、カスタム統合)では、API Gateway はクライアントからのリクエストデータがどのように統合リクエストにマッピングされるかを指定する必要があります。また、統合レスポンスデータの結果がメソッドレスポンスにどのようにマッピングされるかも同様に指定が必要です。
Lambda プロキシ統合と CORS の関係と影響
CORS で通信をするためには API Gateway からのレスポンスに オリジンヘッダが含まれた CORS ヘッダがあればよいので、API Gateway の CORS 有効化設定を行えば良さそうです。 しかし、前述した通り プロキシ統合が有効化されている場合は一定の形式に従って Lambda からのレスポンスがクライアントに直接返答されるため、 API Gateway に CORS の設定をしても意味がなく、Lambda 自体にヘッダの付与を行う必要があります。
実際の設定例
では、実際にマネジメントコンソールから公式ドキュメントに沿って設定を行っていきます。
Lambda プロキシ統合の場合
上記で Lambda プロキシ統合の CORS への影響について説明したのでそのまま先に Lambda プロキシ統合の設定例を示します。
API Gateway 側では特に何も行わず、バックエンドの Lambda 関数のコード自体に公式ドキュメント内の例や以下画像の様にヘッダを付与します。
一定の形式に沿ってレスポンスを API Gateway に返す必要があるため、Lambda で使用している言語の文法に従い headers
キーの中に許可する内容を入力することで設定は完了です。
例では CORS ヘッダに *
を入力していますが、上で添付した図の S3 のオリジンのみだけに許可したい場合は
'headers': { "Access-Control-Allow-Origin": "http://xxx.s3-website-ap-northeast-1.amazonaws.com", }
のようにオリジンを指定して記載します。
非プロキシ統合の場合
公式ドキュメントには非プロキシ統合の場合のマネジメントコンソールからの設定方法がスクリーンショット付きでかなり丁寧に記載されていましたが、少し注意点がありましたので補足しながら設定を行っていきます。
まず、CORS の設定を行いたいリソースを選択し、Enable CORS(CORS の有効化)を押下します。
必要であればゲートウェイレスポンス(API レベルのエラーが CORS エラーで返ってしまう)を選択、対象メソッドにチェックを入れるのを忘れないようにしてヘッダとオリジンを入力します。
この設定により、OPTION メソッドの追加と合わせて以下図のように統合レスポンス(バックエンド Lambda からのレスポンスをカプセル化、マッピングする)に Access-Control-Allow-Origin
ヘッダがマッピングされるようになります。
さらに、メソッドレスポンス(API Gateway からクライアントへのレスポンス)のレスポンスヘッダにも Access-Control-Allow-Origin
が追加されることで実際にクライアントへ CORS ヘッダが渡されるようになり、設定は完了です。
ANY メソッドの場合の注意点
あまり多くはないかもしれませんが、検証等で API Gateway にて ANY メソッドで Lambda 統合を行っている場合上記の手順では CORS の設定が行われないので注意が必要です。
CORS を有効化する場合にチェックボックスに ANY メソッドが出てきません。
そのまま設定をしても、OPTIONS メソッドは自動で追加されますが、CORS アクセスは拒否されてしまいます。
上記 GET メソッド でCORS の有効化をコンソールから設定した時、統合レスポンスとメソッドレスポンスに自動で追加されていた Access-Control-Allow-Origin
が ANY メソッドの場合は作成されません。
この場合、メソッドレスポンスのヘッダ名に Access-Control-Allow-Origin
を追加し、マッピング先に許可したいオリジンを追加することで設定が完了します。
API Gateway からのレスポンス形式
以上で Lambda プロキシ統合による設定方法の違いは確認できましたが、実際にどんな形式でレスポンスが返ってくるか見てみます。 API Gateway の URL を
- https://xxx.execute-api.ap-northeast-1.amazonaws.com/dev/get-method/integration ... プロキシ統合リソース
- https://xxx.execute-api.ap-northeast-1.amazonaws.com/dev/get-method/no-integration ... 非プロキシ統合リソース
とします。
さらにどちらのリソースも バックエンド Lambda でAccess-Control-Allow-Origin
ヘッダでオリジンhttps://xxx.s3.ap-northeast-1.amazonaws.com
と Hello from Lambda!
メッセージを返す設定を行います。また、非プロキシ統合リソースには API Gateway でも CORS をオリジン *
で有効化します。
プロキシ統合リソースのレスポンス
$ curl -i 'https://xxx.execute-api.ap-northeast-1.amazonaws.com/dev/get-method/integration' HTTP/2 200 date: Tue, 05 Dec 2023 17:28:38 GMT content-type: application/json content-length: 20 x-amzn-requestid: 7a64925e-3548-4e9d-b7d2-5f878ede1990 access-control-allow-origin: https://xxx.s3.ap-northeast-1.amazonaws.com x-amz-apigw-id: PeuXHFoLNjMEahQ= x-amzn-trace-id: Root=1-656f5dc6-29722728323b8e8966a0bdcd;Sampled=0;lineage=86e9ce38:0 ⏎ "Hello from Lambda!"%
まずはプロキシ統合リソースに curl -i
コマンドでレスポンスヘッダとボディの両方を出力した結果となります。
ボディには Lambda からのレスポンスの body
と同じHello from Lambda!
が格納されています。さらに、上記の設定通りバックエンド Lambda で定義したオリジンhttps://xxx.s3.ap-northeast-1.amazonaws.com
がヘッダ部分に付与されていることが確認できます。
非プロキシ統合リソースのレスポンス
$ curl -i 'https://xxx.execute-api.ap-northeast-1.amazonaws.com/dev/get-method/no-integration' HTTP/2 200 date: Tue, 05 Dec 2023 17:26:50 GMT content-type: application/json content-length: 151 x-amzn-requestid: 9309034d-af13-448e-bdb4-7b51b6382a80 access-control-allow-origin: * x-amz-apigw-id: PeuGHHNBNjMETNw= x-amzn-trace-id: Root=1-656f5d5a-00de06f2639c55c556bcf42c;Sampled=0;lineage=86e9ce38:0 ⏎ {"statusCode": 200, "body": "\"Hello from Lambda!\"", "headers": {"Access-Control-Allow-Origin": "https://xxx.s3.ap-northeast-1.amazonaws.com"}}%
次に非プロキシ統合リソースにて同様にコマンドを実行した結果となります。
こちらではボディに Lambda からのレスポンス(ステータスコード、ヘッダ、ボディの情報)が全て格納されていました。さらにレスポンスのヘッダには API Gateway 側で設定した CORS ヘッダ *
が付与されていることが確認できます。
レスポンス結果からわかる Lambda プロキシ統合と CORS 設定
上記の結果の通り、プロキシ統合を有効化したレスポンスでは、Lambda からのレスポンスがそのままメソッドレスポンスのヘッダとボディとしてクライアントへ返ってきてきました。つまりプロキシ統合時に CORS を有効化するためには バックエンド Lambda 側で CORS ヘッダを返すということで納得です。
一方非プロキシ統合では、バックエンド Lambda で設定したはずの CORS ヘッダは実際のメソッドレスポンスには付与されておらず、ボディ部分に Lambda からのレスポンスが格納されていました。メソッドレスポンスの ヘッダ情報の中には API Gateway 側で設定した CORS ヘッダの情報が付与される形となっており、API Gateway で CORS 有効化を行う必要があるのも納得です。
API Gateway のCORS 設定方法まとめ
最後に、本ブログで紹介した CORS の設定方法のまとめとなります。
- Lambdaプロキシ統合の場合
- バックエンド Lambda で
Access-Control-Allow-Origin
ヘッダを付与する - Lambda からのレスポンスがそのままクライアントへのメソッドレスポンスとして送信される
- バックエンド Lambda で
- 非プロキシ統合の場合
- API Gateway から CORS の有効化を行う
- CORS の有効化により、レスポンスヘッダのマッピングが追加される
- ANY メソッドを使用する場合は注意が必要
- Lambda からのレスポンスはメソッドレスポンスのボディ部分に格納されている
おまけ:HTTP API の CORS 設定
HTTP API の場合は、Lambda プロキシ統合といった設定項目がありません。 ナビゲーションバーの位置に CORS の欄があるので、そこから CORS の設定を行うことが可能です。
最後に
本ブログの記載によって、Lambda プロキシ統合と API Gateway での CORS の関係を理解しながら、実際に設定することで Lambda プロキシ統合についても改めて確認できたのではないかと思います。また、非プロキシ統合の ANY メソッドでの挙動の確認によって、CORS の設定が OPTIONS メソッドの追加と合わせて対象メソッド内にマッピングが自動で追加されることも確認できました。 本ブログが API Gateway で CORS を設定する際の参考や理解に繋がれば幸いです。
末廣 満希(執筆記事の一覧)
2022年新卒入社です。ここに何かかっこいい一言を書くことができるエンジニアになれるように頑張ります。