Lambda@Edge で URLパスを書き換える
こんばんは、藤本です。
Lambda@Edge を公式ドキュメントに記載されたユースケース以外でどう使うのかいまいちピンとこなかったので、具体例を考えてみました。
ユースケースの公式ドキュメントは下記をご参照ください。
Lambda@Edgeは現在プレビュー段階のため、利用には事前に申請が必要です。また、正式リリース時にサービス仕様が変更される可能性があることをご承知おきください。
AWS Lambda@Edge
AWS Lambda@Edge はエッジロケーションで Lambda Function を実行できる機能です。現在は CloudFront へのイベントをトリガーに Lambda Function を実行できます。現在対応しているイベントは下記 4種類となります。
- リクエストが最初にビューアから届いたとき (ビューアリクエスト)。
- Lambda 関数がオリジン (オリジンの応答) からのレスポンスを受け取るとき。
- Lambda 関数がリクエストをオリジン (オリジンのリクエスト) に転送するとき。
- Lambda 関数がエンドビューア (ビューアの応答) に対応する前。
Lambda@Edge に関しては下記エントリをご参照ください。
CloudFront における URL パス書き換え
先日、Apache の mod_rewrite で各種サブシステムにリバースプロキシしている Web システムにおいて、CloudFront にリバースプロキシ機能を移行することでリバースプロキシしているサーバーの負荷を軽減することを検討しました。結果としては、いくつかの RewriteRule は CloudFront に移行することができましたが、書き方によっては CloudFront へ移行できませんでした。具体的には CloudFront は URL のパスをそのままか、パスを前に足すことしかできません。パスの一部を削除したり、書き換えたりができません。
- ◯:そのままのパス
- http://example.com/sub/index.html で受けたアクセスを
- http://sub.example.com/sub/index.html でアクセスすることはできる
-
◯:パスプレフィックスを追加する
- http://example.com/sub/index.html で受けたアクセスを
-
http://sub.example.com/add/sub/index.html でアクセスすることはできる
-
✕:パスプレフィックスを削除する
- http://example.com/sub/index.html で受けたアクセスを
-
http://sub.example.com/index.html でアクセスすることはできない
-
✕:パスを書き換える
- http://example.com/sub/index.html で受けたアクセスを
- http://sub.example.com/sub/index.php でアクセスすることはできない
構築中のシステム、規模が小さいシステムであれば、Web システムを変更することで対応できるかもしれませんが、既に運用中の Web システムとなると簡単にはいきません。AWS Lambda@Edge を利用することで Web システムを変更することなく対応できるのではないかと思い、試してみました。
試してみた
今回は下記のようなシチュエーションを試してみました。
CloudFront の特定のパスでアクセスを受けた時に Lambda@Edge が発火して、URLパスのプレフィックスを外して、オリジンである S3 の静的ウェブホスティングへアクセスします。
Lambda 関数作成
Lambda@Edge の Lambda Function の作成手順はAWS Lambda@EdgeでスケーラブルなIoTバックエンド構築をご参照ください。IAM Role への信頼関係の追加も忘れずに。
ソースコードは URL の先頭のパスを書き換えるだけのシンプルなものです。
'use strict'; exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; request.uri = request.uri.replace(/^\/sub3/g, ''); callback(null, request); };
CloudFront Behavior への設定
CloudFront ディストリビューションの Behavior から Lambda@Edge を設定します。ARN を指定することで紐付けることができます。
設定はこれだけです。
動作確認
S3 の静的ウェブホスティングを利用して、CloudFront のオリジンを作っています。ファイルはバケット直下にindex.html
のみを配置しています。
$ aws s3 ls --recursive s3://sub3-xxxxxx/ 2017-03-02 20:03:17 10 index.html $ aws s3 cp s3://sub3-xxxxxx/index.html - indexpage
設定前にアクセスすると、ファイルがないので 403 ページが返ってきます。
$ curl http://xxxxxxxxxxxx.cloudfront.net/sub3/index.html <h1>403 Forbidden</h1> <ul> <li>Code: AccessDenied</li> <li>Message: Access Denied</li> <li>RequestId: 001A79DF0FA9C46B</li> <li>HostId: JhhXpegB55Sqf0QbnFkcASydy1+co/CQqYzpqV1hPupsmLfkD+xHuYgZ8NK2uwtn8cnvFPDLP8w=</li> </ul> <hr />
設定後に確認すると、index.html
の中身を取得することができました。
$ curl http://xxxxxxxxxxxx.cloudfront.net/sub3/index.html indexpage
まとめ
いかがでしたでしょうか? Lambda@Edge は今まで困ったことを色々と対応できそうです。考えたら色々と利用用途が思いつきました。他も試してみてブログにまとめたいと思います。