Amazon CloudFrontとAWS Lambda@EdgeでSPAのBasic認証をやってみる
どうも!大阪オフィスの西村祐二です。
特定のユーザにしかログインできないように、 サイト自体にBasic認証をかけたい時があると思います。
今回はS3でホスティングするSPAを想定して、 Amazon CloudFrontとAWS Lambda@Edgeを使ってBasic認証をかけたいと思います。
構成図
完成画面
完成後下記のような挙動になります。 ブラウザ上にURLを入力してアクセスすると、Basic認証の画面が表示されます。 認証が通ったら、S3に保存されているWEBページが表示されます。
作業手順
- S3でSPA用のバケット作成
- CloudFrontのディストリビューションを作成
- Lambda@Edge用のLambda関数作成
- 作成したLambda関数でトリガーをCloudFrontに設定
S3での作業
SPAの静的ファイルを設置するためにバケットを作成します。 リージョンは「東京リージョン」で作成しています。 バケット名は今回「test-lambda-edge」としました。 ログ出力用に「test-lambda-edge-log」も一緒に作成しておくとよいかもしれません。
テストファイルを配置
SPAを想定して、今回下記の静的ファイル「index.html」をS3バケットの「test-lambda-edge」に設置しておきます。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Test Basic Authentication</title> </head> <body> <p>Hello World!! Passed Basic Authentication!</p> </body> </html>
S3カスタムオリジンで利用するため、Webホスティング設定は実施しません。
CloudFrontのディストリビューションを作成
▼マネージメントコンソールから作成していきます。「Create Distribution」をクリックします。
▼Webを選択します。
▼下記のように設定していきます。
▼TTLは各自適当な設定を行ってください。今回コンテンツの更新をすぐ確認したかったため、無効化しています。
確認
▼作成したディストリビューションが「Deployed」であることを確認します。
▼HTTPでアクセスできないこと
▼HTTPSでアクセスできること
Lambda関数の作成
次にCloudFrontのエッジロケーションに配置するLambda関数を作成していきます。
IAMロールの作成
まず、Lambda@Edge用のIAMロールとポリシーの設定を行います。
▼IAMのマネージメントコンソールから設定していきます。
▼「信頼されたエンティティ」でLambdaをクリックし「次へ」のボタンをクリックします。
▼作成するロールにアタッチするポリシーを作成します。
▼新しいタブが開き、ポリシーを作成する画面に移動します。 JSONのタブをクリックして、下記のポリシーを貼り付けます。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": [ "lambda:GetFunction", "lambda:EnableReplication*", "iam:CreateServiceLinkedRole", "cloudfront:CreateDistribution", "cloudfront:UpdateDistribution" ], "Resource": "*" } ] }
▼ポリシーの名前を「test-lambda_edge_exection」としてポリシーを作成します。
▼ロール作成のタブに戻り、「更新」ボタンをクリックし、検索窓から検索し、作成したポリシーを選択し、次へ行きます。
▼ロール名を「test-lambda_edge_exection」としてロールを作成します。
▼信頼関係に「edgelambda」を追加します。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com", "edgelambda.amazonaws.com" ] }, "Action": "sts:AssumeRole" } ] }
これで、IAMロールとポリシーの設定は完了です。
Lambda@Edgeの注意点
※2018/1/5時点の情報となります。 通常の作成方法とは異なりいくつかハマりポイントがあります。Lambda関数を作成する前に、Lambda@Edgeの注意点についてまとめておきます。
詳細はドキュメントを参照ください。
- ランタイム:Node.js 6.10のみ対応?
- リージョン:米国東部(バージニア北部)で作成する必要あり
- メモリサイズ:128MBまで
- 実行時間:
- ビューワーリクエストおよびビューワーレスポンスイベント:1秒
- オリジンリクエストおよびオリジンレスポンスイベント:3秒
- Lambda関数のファイルサイズ:1MBまで
- バージョニングを使用する必要あり、$Latest は指定できない
- /tmp は利用不可
- 環境変数, Dead Letter Queue, Amazon VPCsは利用不可
Lambda@Edgeのイベント
今回行うBasic認証はビューアリクエストのイベントに該当します。
Lambda関数の作成
▼マネージメントコンソールから作成していきます。
▼「一から作成」を選び、名前「S3-basic-authentication」、ランタイム「Node.js 6.10」、作成したIAMロールを設定して関数を作成します。
▼実行時間の設定をビューアリクエストの制限をこえないように「1秒」に設定します。
実際のプログラムはこちらを参考にさせていただきました。
'use strict'; exports.handler = (event, context, callback) => { // Get request and request headers const request = event.Records[0].cf.request; const headers = request.headers; console.log('request: ' + JSON.stringify(request)); // Configure authentication const authUser = 'user'; const authPass = 'pass'; // Construct the Basic Auth string const authString = 'Basic ' + new Buffer(authUser + ':' + authPass).toString('base64'); // Require Basic authentication if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) { const body = 'Unauthorized'; const response = { status: '401', statusDescription: 'Unauthorized', body: body, headers: { 'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}] }, }; callback(null, response); } // Continue request processing if authentication passed callback(null, request); };
ここまで設定ができたら「保存」をクリックしておいてください。
バージョニングの設定
LambdaをCloudFrontのエッジロケーションに配置するためにトリガーをCloudFrontに設定するのですが CloudFront イベントを $LATEST またはエイリアスと関連付けることはできません。
そのため、バージョン設定を行う必要があります。
▼アクションから「新しいバージョンを発行」をクリックします。
▼バージョンを発行します。
▼発行されたら下記のような表示がされます。
トリガー設定
Lambda@Edgeとして、CloudFrontのエッジロケーションにLambda関数を設定するためには Lambda関数のトリガーをCloudFrontにする必要があります。
▼作成したディストリビューションのIDを設定し、イベントに「ビューアリクエスト」を設定し追加します。
▼その後「保存」ボタンをクリックすると、CloudFrontのディストリビューションのステータスが「In Progress」になります。
▼ステータスが「Deployed」になったら、エッジロケーションにLambda関数のデプロイが完了したということになります。
Basic認証の動作確認
CloudFrontのURLにアクセスしてみると想定通り Basic認証のログインアラートが表示されています。
さいごに
いかがだったでしょうか。
Amazon CloudFrontとAWS Lambda@EdgeでSPAのBasic認証をやってみました。 Lambda@Edgeはエッジロケーションへのデプロイまで時間がかかったり 作成時に制限などがありますが、いろいろなことに活用できそうだなと思いました。
誰かの参考になれば幸いです。
参考サイト
http://blog.jicoman.info/2017/10/s3-basic-using-cloudfront-lambda-edge/
https://qiita.com/sumikawa@github/items/0344a2920f2438dea3b5
https://gist.github.com/lmakarov/e5984ec16a76548ff2b278c06027f1a4
http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-edge.html#lambda-edge-testing-debugging