はじめまして。カヤック技術部の杉山です。 主にクライアントワークでサービスを開発しています。
今回は、自分の好きなCloudFrontの「Lambda@Edge」について書きます。
Lambda@Edgeとは
基本的にはここに使い方が書いてありますが、 開発者ガイド > AWS Lambda@Edge
CloudFrontへのアクセス、または応答時に、機能制限されたLambda functionを実行することが出来る機能です。 アクセス時や、応答時に副作用を起こすこと、レスポンス自体を変えることが出来ます。
実際はまだプレビュー版なので、まず申請する必要がありますが、 数日待ち許可されると、1つだけCloudFront にLambda functionを割り当てることが可能になります。
たとえばこんな物が作れます
副作用を起こすLambda functionは想像しやすいと思うので、 今回はレスポンス自体を置き換える例を作ってみました。
以下に示す二つの例はどちらも、リクエスト時に呼ばれるトリガーにLambda functionを割り当てる必要があります。
大まかにいうと、callback に、リクエストとして届いたデータをそのまま渡せば、通常通りの処理となり、 ステータスコードとともにbodyやレスポンスヘッダを返せば、好きなレスポンスに置き換えられます。
時間を返すAPIとか
exports.handler = (event, context, callback) => { const time = () => { const date = new Date() ; return Math.floor(date.getTime() / 1000); }; const request = event.Records[0].cf.request; const now = time(); const response = { status: '200', statusDescription: 'HTTP OK', httpVersion: request.httpVersion, headers: { "Content-Type": ["application/json; charset=utf-8"], }, body: `{"times":${now}}`, }; callback(null, response); };
負荷テストをしたところ、100req/sec 以上の速度が出ていましたが、同時アクセスが増えると、503 エラーが表示されました。 CloudFrontにCloudFrontを入れるような日が来るかもしれません。
BASIC認証とか
exports.handler = (event, context, callback) => { const Allows = { "users": "users", }; const request = event.Records[0].cf.request; const headers = request.headers; const authorization = headers.authorization || headers.Authorization; if (authorization) { const enc = authorization[0].split(" ")[1]; const userPassword = new Buffer(enc, 'base64').toString(); for (var key in Allows) { var val = Allows[key]; if (`${key}:${val}` === userPassword) { callback(null, request); return; } } } const response = { status: '401', statusDescription: 'Authorization Required', httpVersion: request.httpVersion, headers: { "WWW-Authenticate": ['Basic realm="Enter username and password."'], "Content-Type": ["text/plain; charset=utf-8"], }, body: "401 Authorization Required", }; callback(null, response); };
リクエストヘッダーに含まれるキーが、大文字と小文字どちらの場合もありました。おそらく今後、統一されると思います。
Viewer リクエスト時のヘッダー例
{ "uri":"/hoge", "method":"GET", "httpVersion":"1.1", "clientIp":"**.**.**.**", "headers":{ "Host":["hoge.kayac.com"], "Connection":["keep-alive"], "Cache-Control":["max-age=0"], "Upgrade-Insecure-Requests":["1"], "User-Agent":["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"], "Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"], "Accept-Encoding":["gzip, deflate, sdch"], "Accept-Language":["ja,en;q=0.8,en-US;q=0.6"] } }
困ったところ
Lambda function の関数を書き換えたときに、反映までしばらく待つ必要があることと、 CloudFront経由のアクセスは、console.log が表示されないのが、開発でなかなかつらいポイントです。
さいごに
面白いことが他にもできそうで、正式リリースが待ち遠しいです。
新しい物がでたらすぐに試して導入できるのも、クライアントワークの楽しいところです。
こんな仕事が面白そうだと思った人はこちらから! 杉山のブログを読んだと書いてもらえると、筆が進みます。