S3+CloudFront+Route 53を使った静的コンテンツ配信 Part 2 (lambda@edge編)

福岡拠点の野田です。

前回、S3を使った静的コンテンツ配信を実現しましたが、ちょっとカッコ悪い点がありました。

ドメイン直下については、 Default Root Object 設定すると https://サイト名/でアクセスしたときindex.html を参照するようにできます。ただし、サブディレクトリ配下はDefault Root Objectの設定が効きません。サブディレクトリ配下で/news/とアクセスしたとき、/news/index.htmlを参照するためにはlambda@edgeを使う必要があります。

/で終わるuriの場合に/index.htmlを参照する設定について、今回は以下の流れで設定を行います。

  1. lambdaを追加
  2. CloudFrontで使えるようにIAMを修正
  3. lambdaにトリガーを追加し、CloudFrontと関連付け

lambdaを追加

リージョンus-east-1のlambda画面から関数を追加します。ほかのリージョンではCloudFrontへのトリガーを作成できないため、正しいリージョンが選択されているか確認してください。

https://console.aws.amazon.com/lambda/home?region=us-east-1

lambdaは1から作る形で進めます。

・関数名:subdir-redirect (適宜適当な名前を設定してください)
・ランタイム:nodejs (バージョンはデフォルトでOK)
・アクセス権限:AWSポリシーテンプレートから新しいロールを作成
・ロール名:cloudfront-lambda (適宜適当な名前を設定してください)
・ポリシーテンプレート:基本的なlambda@edgeのアクセス権限

関数詳細ページが表示されるので、関数コードに以下を追加します。

'use strict';
exports.handler = (event, context, callback) => {
    var request = event.Records[0].cf.request;
    request.uri = request.uri.replace(/\/$/, '\/index.html');
    return callback(null, request);
};

画面右上の「保存」を押下してコードを保存します。

CloudFrontで使えるようにIAMを修正

そのままでは使うことができないため、関数詳細ページ「アクセス権限」のタブを選択します。実行ロール「 cloudfront-lambda 」を編集し、末尾の「 IAM コンソールで cloudfront-lambda ロールを表示します。」のリンクをクリックします。

ロールの詳細ページから「信頼関係」のタブをクリックします。「信頼関係の編集」ボタンを押下して、以下のようにedgelambdaの設定を追加します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "lambda.amazonaws.com",
          "edgelambda.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

これにより信頼されたエンティティにedgelambdaが追加されます。

信頼されたエンティティ
ID プロバイダー lambda.amazonaws.com
ID プロバイダー edgelambda.amazonaws.com

続いて「アクセス権限」のタブに再度戻ります。+インラインポリシーの追加から以下のポリシーを追加します。

  • Lambda: GetFunction, EnableReplication (対象リソースは、先ほど登録したsubdir-redirect lambda のARNを指定)
  • IAM: CreateServiceLinkedRole(対象リソースはすべて)
  • CloudFront: UpdateDistribution(対象リソースは、展開するCloudFrontのARNを指定)

ここまでやってようやくlambda@edgeが使えるようになります。

lambdaにトリガーを追加し、CloudFrontと関連付け

仕上げにlambdaの関数詳細画面に戻ります。画面上の「アクション」から新しいバージョンを発行します。コメントは必要あれば適宜入力してください。

そののちにデザイナーから「トリガー」を追加します。トリガーの種類は、CloudFrontを選択します。ここでCloudFrontが選択できない場合はlambdaのリージョンが間違っていますので、最初からやり直してください。設定はデフォルトのままで以下のチェックボックスにチェックを入れます。

 Lambda@Edge へのデプロイを確認 
関数のこのバージョンが上記のトリガーと関連付けられ、利用可能なすべての AWS リージョン間でレプリケートされることに同意します。 

追加ボタンを押下するとCloudFrontへの更新が入ります。Distributionの更新が終わるまでしばし待つと、晴れてサブディレクトリのリダイレクト処理を利用することができるようになります。

まとめ

lambdaというと単機能のAPIや軽量サーバーとして使うイメージが強いですが、実はいろいろなところに組み込めます。lambda@edgeを利用することでCloudFrontに対してヘッダーのカスタマイズ、 BASIC認証など多岐にわたって処理を組み込むことができます。静的コンテンツに対してちょっとした動的処理を行いたいな、というときはlambda@edgeの出番です。是非ご活用いただければと思います。

面倒なところもありますが、ひと手間かけるといろいろなことができるのがAWSの良いところ。いろいろエンジニアとしていろいろHackしていければと思います。