Lambda@Edge で URLパスを書き換える

AmazonLambda

こんばんは、藤本です。

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 でアクセスすることはできない


before-rewrite

構築中のシステム、規模が小さいシステムであれば、Web システムを変更することで対応できるかもしれませんが、既に運用中の Web システムとなると簡単にはいきません。AWS Lambda@Edge を利用することで Web システムを変更することなく対応できるのではないかと思い、試してみました。

試してみた

今回は下記のようなシチュエーションを試してみました。

after-rewrite

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 を指定することで紐付けることができます。

AWS_CloudFront_Management_Console

設定はこれだけです。

動作確認

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
<html>
<head><title>403 Forbidden</title></head>
<body>
<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/>
</body>
</html>

設定後に確認すると、index.htmlの中身を取得することができました。

$ curl http://xxxxxxxxxxxx.cloudfront.net/sub3/index.html
indexpage

まとめ

いかがでしたでしょうか? Lambda@Edge は今まで困ったことを色々と対応できそうです。考えたら色々と利用用途が思いつきました。他も試してみてブログにまとめたいと思います。

AWS Cloud Roadshow 2017 福岡