AWS
lambda
Lambda@Edge

Lambda@Edgeを使えば、CloudFrontでの配信にカスタムヘッダーを付与できる話

今までLambdaをさわってきたものの、未体験だったLambda@Edgeを使ってみた話です。

2016年のre:Inventで発表されたサービスであり、新しいものではありません。

記事中では、Labda@Edgeに関する情報と、S3においた静的ファイルをCloudFrontで配信している場合に、カスタムヘッダーを付与する方法を事例として紹介してます。

Lambda@Edgeとは

クライアントからCloudFrontにアクセスしたときの、特定のタイミング(後述)でLambda関数を実行できるサービスです。

実行されるタイミング

Lambda関数が実行されるタイミングとしては、

以下の四つがあります。

タイプ 実行のタイミング ユースケース例
Viewer Request CloudFront がEnd userからリクエストを受信した後 CloudFrontで配信しているサイトにBasic認証をかけたいとき
Viewer Response CloudFront がEnd userにレスポンスを転送する前 CloudFrontで配信している場合に、カスタムヘッダーを付与したいとき
Origin Request CloudFront がリクエストをOriginサーバーに転送する前 CloudFront の特定のパスでアクセスを受けた時に、そのURLを書き換えたいとき
Origin Response CloudFront がOriginからレスポンスを受信した後 Originから返却されたレスポンスがエラーステータスコードで、 それを200-OK に更新したいとき

cloudfront-events-that-trigger-lambda-functions.png
(引用 https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-edge.html)

本記事の具体例においてはOrigin serverがS3となります。

制約

制約は結構あります(2018年3月現在)。目立ったところを記述すると

  • バージニア北部をリージョンとして使う必要がある。
  • 追加できるHTTPのヘッダーに制限がある。
  • Lambda関数の実行時間、最大圧縮サイズに制限がある。
  • 実行環境としては、Node.js 6.10しかない。
  • Originイベント(CloudFrontとOriginサーバ間でのイベント)とViewイベント(End UserとCloudFront間でのイベント)で実行できるリソースの量が異なる。Originイベントのほうが制約が緩い。
  • コードからのネットワーク通信不可(DB等にアクセスできない)

詳細はこちら

使ってみた

状況

S3で静的ファイルを配信している。CloudFrontフロント経由で配信しているが、カスタムヘッダーを付与したい。

これを実現するには以下のステップを踏みます。

  • Lambda@Edge用のIAMロールの作成
  • Lambda@Edge用のLambda関数作成
  • Lambda@EdgeをCloudFrontと紐付ける

作業の前提として

  • S3のバケット
  • CloudFrontでの配信

の作成/設定はできているものとします。

IAMロールの作成

作成するIAMアクセス権限としては、Lambda 関数を CloudFront ディストリビューションに関連付けるために次の IAM アクセス権限が必要です。

詳細は、

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-edge.html

「Lambda@Edge 用の IAM アクセス権限とロールの設定」のセクションを参考にください。

忘れやすい注意点としては、サービスプリンシパル lambda.amazonaws.com と edgelambda.amazonaws.com が引き受けることができる IAM ロールを作成する必要があります。

実作業しては、「Edit Trust Relationship」でlambda.amazonaws.com, edgelambda.amazonaws.comを追加します。

Lambda関数作成

カスタムヘッダに、Content Security Policyに関する情報を追加したいとします。コードは以下のようになります。

exports.handler = (event, context, callback) => {
    const response = event.Records[0].cf.response;
    const headers = response.headers;

    headers['content-security-policy'] = [{
        key:   'Content-Security-Policy', 
        value: "default-src 'self'"
    }];

    callback(null, response);
};

コード記述したあとは、バージョニングをする必要があります。Lambda関数の画面上部の「Actions」より「Publish New Version」をクリックすることで可能です。バージョニングしたものに関しては、「Add Triggers」よりCloudFrontが選択可能になります。

CloudFrontと紐付ける

CloudFrontを追加したあとは以下のような画面が出るので、そちらを記入していきます。DistributionにはCloudFront DistributionのIDを入れます。

スクリーンショット 2018-03-18 0.11.54.png

記入したら、関数のSaveを忘れないようにしましょう。

CloudFrontの方の画面を確認すると、StatusがDeploy中になり、Deployされると、実際にHttp Headerに追加されていることが確認できます。

参考

AWS Lambda@Edge
CloudFront と Lambda@Edge の使用 » 関数の例 <- 自分がyく確認するURL
Amazon CloudFrontとAWS Lambda@EdgeでSPAのBasic認証をやってみる
Lambda@Edge で URLパスを書き換える
Serving custom headers from static sites on CloudFront/S3 with Lambda@Edge