Lambda@Edge とは
CloudFront へのリクエスト時に Lambda 関数を実行して何かやるすごい仕組み。
- A/B テスト
- 認証、アクセス元IP制限
- レスポンスヘッダ追加・書き換え (リダイレクトなど)
- むしろ Lambda 関数で動的にレスポンスボディも作っちゃう
- オリジンの動的切り替え
- その他いろいろ
@Edge
と謳っている通り、世界中の CloudFront エッジロケーションへレプリケーションされた Lambda 関数が、各ロケーション内で実行される。
もう、やりたい放題ですね。
実行できるタイミング
4 つのイベント時に関数を仕込める。
・ CloudFront がビューワーからリクエストを受信した後 (ビューワーリクエスト)
・ CloudFront がリクエストをオリジンサーバーに転送する前 (オリジンリクエスト)
・ CloudFront がオリジンからレスポンスを受信した後 (オリジンレスポンス)
・ CloudFront がビューワーにレスポンスを転送する前 (ビューワーレスポンス)
Lambda@Edge – AWS Lambda
制限
HTTP リクエスト時に同期的に Lambda 関数を実行するので、言うまでもなく、数分間処理をぶん回すなんてことはできない。 その他にもいろいろ制限があるので、要チェック。
インパクト大きいのは主に下記かと。
- 環境変数: 使えません
- ランタイム: Node.js 6.10 or 8.10 のみ
- メモリ: 128 MB
- 関数タイムアウト: 30 秒 (オリジンリクエスト、レスポンス) / 5 秒 (ビューワーリクエスト、レスポンス)
その他にもいろいろ制限がある。
Basic 認証をかけてみた
前提
CloudFront のディストリビューションはすでに設定済みであること。
CloudFront から Lambda 関数を実行するための IAM ロール設定
他の AWS サービスにアクセスしない単純な関数の場合、Lambda と CloudFront のサービスが AWSLambdaBasicExecutionRole
を引き受けられるように設定すれば良い。
マネジメントコンソールの IAM のロール作成画面より、下記の流れで作成。
AWSLambdaBasicExecutionRole
ポリシーをアタッチ。
ロール名、説明は適宜設定し、一旦追加する。
追加したロールの信頼関係の編集画面にて、edgelambda.amazonaws.com
を追加。
Lambda 関数の準備
関数作成
マネジメントコンソールの Lambda 関数作成画面から作成。
バージニア北部リージョン (us-east-1
) に作成しないと駄目なので注意。
- 名前: 適当に
- ランタイム: 先に述べたとおり、Node.js 6.10 or 8.10 を選択
- ロール: 先程追加したロールを選択
コードについて
CloudFront にはサクッと認証かける術がないので、Basic 認証をかける方法は需要がある。 そのため、ググればいくらでも先例が出てくるので、下記のコードを拝借して試してみた。
出典: Serverless: password protecting a static website in an AWS S3 bucket
認証情報がコード内にべた書きなので、AWS Systems Manager パラメータストア などに移したいところだが、後述の通り、ビューワーリクエストの関数タイムアウトが 5 秒しか無いのにネットワークアクセスが発生するのは少々悩ましいところ。
細かい設定
制限に沿うように設定。
- タイムアウト: 5 秒
- メモリ: 128 MB
バージョン発行
CloudFront には Lambda 関数の特定バージョンしか指定できないので、新しいバージョンを発行しておく。
CloudFront のビューワーリクエストイベントに Lambda 関数を関連付け
ブラウザからのアクセス時に必ず認証を行うために、ビューワーリクエストイベントをトリガーとして実行するように設定。
CloudFront が受信したディストリビューションのすべてのリクエストに対して関数を実行する場合は、ビューワーリクエストイベントかビューワーレスポンスイベントを使用します。
オリジンリクエストイベントとオリジンレスポンスイベントは、リクエストされたオブジェクトがエッジロケーションにキャッシュされていないためにリクエストがオリジンに転送される場合にのみ発生します。
Lambda 関数をトリガーするために使用する CloudFront イベントを決定する方法
CloudFront のビヘイビア設定編集画面の最下部で、先程の Lambda 関数 (の特定バージョン) ARN を Viewer Request
と関連付け。
設定後、Lambda 関数の編集画面にて、CloudFront のトリガーが設定されていることを確認。
動作確認
ここまで設定を行えば、CloudFront の対象 URL へアクセス時に Basic 認証が有効になっているはず!
ちなみに、実行ログは各エッジロケーションがあるリージョンの CloudWatch ログに吐かれる。
東京からアクセスした際の Lambda のログは東京リージョンの CloudWatch ログに吐かれる。
備考
厳密にアクセス制限する必要がある場合、CloudFront を迂回したオリジンへの直アクセスを防がないとザルになるので要注意。