CloudFrontFunctionとLambdaEdgeの違い

July 21, 2023

CloudFrontFunction / LambdaEdge について

CloudFront Functions は、Amazon CloudFront のサービスであり、Lambda@Edge より手前で動作し、シンプルな処理を高速かつ安価に実行できるように設計された機能です。従来の Lambda@Edge は、CloudFront のエッジロケーションで動作するカスタムの AWS Lambda 関数を作成して、リクエストまたはレスポンスを処理することができます。一方、CloudFront Functions はよりシンプルで軽量であり、Lambda@Edge よりも低いレイテンシと高いパフォーマンスを持っています。

CloudFront Functions を使用すると、よりユーザーに近いエッジロケーションでリクエストを処理できるため、レスポンス時間が短縮され、ユーザーエクスペリエンスが向上します。また、コスト面でも Lambda@Edge よりも経済的であるため、シンプルな処理には CloudFront Functions が適しています。

さらに、CloudFront Functions と Lambda@Edge を組み合わせて使用することも可能です。例えば、シンプルな処理やヘッダーの操作、URL の書き換えなどのタスクを CloudFront Functions で処理し、より高度な処理を必要とする場合には Lambda@Edge で追加の処理を行うことができます。 これにより、より効率的で高速なコンテンツデリバリーサービスを提供することができるため、AWS のクラウドインフラストラクチャを活用したウェブアプリケーションやコンテンツの配信を行う際に便利です。

比較表

特徴 CloudFrontFunction Lambda@Edge
ランタイムサポート JavaScript (ECMAScript 5.1 準拠) Node.js、Python
実行場所 218 以上の CloudFront エッジロケーション 13 の CloudFront リージョンのエッジキャッシュ
サポートされる CloudFront トリガー ビューアリクエスト、ビューアレスポンス、オリジンリクエスト、オリジンレスポンス ビューアリクエスト、ビューアレスポンス、オリジンリクエスト、オリジンレスポンス
最大実行時間 1 ミリ秒未満 5 秒 (ビューアトリガー)、30 秒 (オリジントリガー)
最大メモリ 2 MB 128 MB (ビューアトリガー)、10 GB (オリジントリガー)
合計パッケージサイズ 10 KB 1 MB (ビューアトリガー)、50 MB (オリジントリガー)
ネットワークアクセス なし あり
ファイルシステムアクセス なし あり
リクエスト本文へのアクセス なし あり
料金 無料利用枠あり。リクエストごとに課金。 無料利用枠なし。リクエストと関数の実行時間ごとに課金。

まとめ・考察

どちらにするかは処理時間か鍵になりそうです。

CloudFrontFunctions は同時実行数のクォータとかが公開されておらず、おそらく無いのではないかと思ってます。

CloudFrontFunctions サンプルコード

実際に使ってみたので CloudFrontFunctions サンプルコードを載っけてみます。

LambdaEdge はロール作ったりデプロイするのが面倒なのですが、CloudFrontFunctions はコードだけ書けばいいので楽ですね。

IP 制限をかける

function handler(event) {
    var request = event.request;
    var viewer = event.viewer;
    var allowIP = ["1.1.1.1", "0.0.0.0"];

    if (allowIP.indexOf(viewer.ip) !== -1) {
        return request;
    }

    return {
        statusCode: 403,
        statusDescription: "Forbidden",
        body: "Access to this resource is forbidden.",
    };
}

www なしから www ありにリダイレクトさせる

var querystring = require("querystring");

// クエリストリングを文字列化するヘルパー関数
function stringifyQueryString(eventQueryString) {
    var query = {};
    Object.entries(eventQueryString).forEach(function (q) {
        query[q[0]] = q[1].multiValue
            ? q[1].multiValue.map(function (m) {
                  return m.value;
              })
            : q[1].value;
    });
    return querystring.stringify(query);
}

function handler(event) {
    var request = event.request;
    var newurl = "https://www.domain.jp" + request.uri;
    // クエリストリングが存在する場合は、文字列化して newurl に追加
    if (Object.keys(request.querystring).length > 0) newurl += "?" + stringifyQueryString(request.querystring);
    return {
        statusCode: 301,
        statusDescription: "Found",
        headers: { location: { value: newurl } },
    };
}

Basic 認証をかける(path によって認証を変える)

  • 処理時間を気にして、予め ID,PW を base64 でエンコードしてます。
function handler(event) {
    var request = event.request;
    var headers = request.headers;
    var viewer = event.viewer;
    var idpw = "dGVzdF8xOnRlc3RfMg=="; // common IDPW
    var allowPathFlag = false;
    var optionPathSettingFlag = false;
    var pathRules = {
        "^/test/*": { idpw: "dGVzdF8xOnRlc3RfMw==" },
        "^/aiu/*": { idpw: "dGVzdF8xOnRlc3RfMw==" },
        "^/hoge/aiu/*": { idpw: null },
    };

    for (var path in pathRules) {
        if (pathRules.hasOwnProperty(path) && new RegExp(path).test(request.uri)) {
            allowPathFlag = true;
            if (pathRules[path].idpw !== null) {
                optionPathSettingFlag = true;
                idpw = pathRules[path].idpw;
                break;
            }
        }
    }

    if (allowPathFlag && !optionPathSettingFlag) {
        return { request: request };
    }

    // IDPW
    var authString = "Basic " + idpw;

    if (typeof headers.authorization === "undefined" || headers.authorization.value !== authString) {
        return {
            statusCode: 401,
            statusDescription: "Unauthorized",
            headers: { "www-authenticate": { value: "Basic" } },
            request: request,
        };
    }

    return { request: request };
}

terraform でデプロイするとき

超カンタン。こんな感じでデプロイできます。

resource "aws_cloudfront_function" "hoge" {
  name    = "hoge-${terraform.workspace}"
  runtime = "cloudfront-js-1.0"
  publish = true
  code    = file("hogehoge.js")
}
Nifty tech tag lists from Wouter Beeftink