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

2017.03.02

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんばんは、藤本です。

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
<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 は今まで困ったことを色々と対応できそうです。考えたら色々と利用用途が思いつきました。他も試してみてブログにまとめたいと思います。