AWS CDK で CloudFront Functions と KeyValueStore を実装する

AWS CDK で CloudFront Functions と KeyValueStore を実装する

Clock Icon2025.03.21

こんにちは、製造ビジネステクノロジー部の若槻です。

Amazon CloudFront Functions で KeyValueStore を使用すると、Distribution の動的な設定管理を CloudFront のエッジロケーションで行うことができます。

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/kvs-with-functions.html

今回は、最近 AWS CDK で CloudFront Functions および KeyValueStore を実装する機会があったので、その方法を改めて確認してみました。

ちなみに前回のブログに比べてよりシンプルな実装で同じ機能が実現できる内容となっているので、そちらを過去に参照いただいたことがある方も改めて本記事もご参照いただければと思います。

実装

Functon コード

下記は CloudFront Distribution にベーシック認証を追加する CloudFront Function のコードです。

lib/function.js
import cf from "cloudfront";

const kvsHandle = cf.kvs(); // Function に関連付けられた KeyValueStore のハンドルを取得

async function handler(event) {
  const request = event.request;
  const headers = request.headers;

  if (
    typeof headers.authorization === "undefined" ||
    typeof headers.authorization.value === "undefined"
  ) {
    return response401;
  }

  const encoded = headers.authorization.value.split(" ")[1];
  const decoded = Buffer.from(encoded, "base64").toString();
  const userRequest = decoded.split(":")[0];
  const passRequest = decoded.split(":")[1];

  const exist = await kvsHandle.exists(userRequest); // キーが存在するか確認
  if (!exist) {
    return response401;
  }

  const passStore = await kvsHandle.get(userRequest); // キーを指定して値を取得
  if (passStore !== passRequest) {
    return response401;
  }

  return request;
}

const response401 = {
  statusCode: 401,
  statusDescription: "Unauthorized",
  headers: { "www-authenticate": { value: "Basic" } },
};
  • JavaScript runtime 2.0 を使用する前提のコードとなっています。
  • 組み込みメソッドの cf.kvs() を使用すると、Function に関連付けられた KeyValueStore のハンドルによるヘルパーメソッドが利用可能になります。
    • ヘルパーメソッド exists() を使うことで、指定したキーが存在するか確認できます。
    • ヘルパーメソッド get() を使うことで、指定したキーに対応する値を取得できます。
    • ドキュメントには cf.kvs(kvsId) のように KeyValueStore の ID を指定する方法が記載されていますが、実際には指定をせずに取得が可能となっています。ちなみに前回のブログでは指定する前提の実装を紹介していました。

CDK コード

CloudFront KeyValueStore と Function を作成し、Distribution に Function を関連付ける CDK コードです。

lib/main-stack.ts
import * as cdk from "aws-cdk-lib";
import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
import * as cloudfront_origins from "aws-cdk-lib/aws-cloudfront-origins";
import { Construct } from "constructs";

export class MainStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props: cdk.StackProps) {
    super(scope, id, props);

    // KeyValueStore の作成
    const keyValueStore = new cloudfront.KeyValueStore(this, "KeyValueStore");

    // Function の作成
    const cloudfrontFunction = new cloudfront.Function(
      this,
      "Function",
      {
        keyValueStore, // KeyValueStore を指定。
        code: cloudfront.FunctionCode.fromFile({
          filePath: "./lib/function.js", // コードを記載したファイルを指定
        }),
      }
    );

    // Distribution の作成
    new cloudfront.Distribution(this, "Distribution", {
      defaultBehavior: {
        origin: new cloudfront_origins.HttpOrigin("classmethod.jp"),

        // Viewer Request 時に Function によるベーシック認証を実行
        functionAssociations: [
          {
            function: cloudfrontFunction,
            eventType: cloudfront.FunctionEventType.VIEWER_REQUEST,
          },
        ],
      },
    });
  }
}
  • KeyValueStore の作成は KeyValueStore L2 コンストラクトクラスを使用して行います。
  • Function の作成は Function L2 コンストラクトクラスを使用して行います。
    • keyValueStore プロパティが指定されている場合は、ランタイムは既定で JavaScript 2.0 となります。

上記実装を CDK デプロイします。

デプロイ後にマネジメントコンソールを確認すると、Distribution の behavior に Function が関連付けられています。

Function の作成および KeyValueStore との紐づけが行われています。

ちなみに CloudFront Function には Live および Development の 2 つのステージがありますが、Function コンストラクトの使用ではステージの概念は無く、いずれのコードおよび KeyValueStore の関連付けも同じ値および設定となります。

KeyValueStore も作成されています。キーペアはまだ何も設定されていません。

動作確認

マネジメントコンソールから KeyValueStore にベーシック認証のユーザー名およびパスに対応するキーペアを設定します。

Distribution URL にブラウザでアクセスするとベーシック認証が求められます。KeyValuesStore に設定されていないキーペアを指定した場合、ベーシック認証が失敗し、401 エラーが返却されて再度認証が求められます。

正しいキーペアを指定すると、リクエストが成功し、オリジンのページが表示されます。

おわりに

AWS CDK で CloudFront Functions と KeyValueStore を実装する方法を改めてご紹介しました。

前回のブログでは Function コード内で KVS ID を指定するために、文字列の replace 処理を掛けたりと冗長な実装をしていましが、実際にはそのような指定は不要であることが分かったのでご紹介差し上げました。本記事が参考になれば幸いです。

以上

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.