Lambda@Edge 不要!CloudFront Functions + KVS で実装するBasic 認証

記事タイトルとURLをコピーする

概要

この記事では 「CloudFront Functions + KeyValueStore を使った Basic認証の実装」 について紹介します。

【本記事でわかること】

  • CloudFront Functions (JavaScript 2.0 ランタイム) で Basic認証を実装する方法
  • マネジメントコンソールを使ったリソース構築手順
  • CloudFront KeyValueStore (KVS) に認証情報を格納して参照する実装

見出し

はじめに

こんにちは!熱い夜が続いているので、もうエアコンをつけてしまいました。クロスインダストリー第2本部 統合運用サービス課の圡井です!

S3 + CloudFront で静的コンテンツを配信する構成はよく使われますが、デフォルトの設定ではURLを知るすべてのユーザーがアクセス可能な状態になっています。ホームページのような公開情報であればよいですが、「特定のユーザーだけにアクセスを制限したい」 というケースもあると思います。

そんなときに便利なのが CloudFront Functions を使った Basic認証です。Lambda@Edge と比べて軽量・低コストで、Viewer Request のタイミングで認証チェックを挟むことができます。 また、現時点(2026年5月)では、CloudFront Functions の実行ランタイムに廃止予定は設定されていないため、長期的に安定して利用できる認証方法 の一つと考えます。

さらに、CloudFront KeyValueStore (KVS) を組み合わせることで、認証情報をコードにハードコードせずに管理できます。

本記事では、マネジメントコンソールを使ってこの構成を構築する手順を紹介します。

前提条件

  • S3 + CloudFront が利用可能な AWS アカウントを持っていること

アーキテクチャ

今回構築する構成は以下のとおりです。

構成図

【ポイント!】

  • CloudFront Functions は Viewer Request イベントで実行します
  • 認証情報は CloudFront KeyValueStore に格納し、関数コードから参照します
  • S3 バケットへの直接アクセスは Origin Access Control (OAC) でブロックします

CloudFront Functions とは

CloudFront Functions は、CloudFront のエッジロケーションで軽量な JavaScript を実行できる機能です。

Lambda@Edge と似ていますが、より高速・低コストで、Viewer Request / Response のタイミングで実行できる点が特徴です。

docs.aws.amazon.com

以下に CloudFront Functions と Lambda@Edge の主な違いをまとめます。

項目 CloudFront Functions Lambda@Edge
ランタイム JavaScript 2.0 *1 Node.js, Python 等
実行タイミング Viewer Request / Response Viewer / Origin の Request / Response
最大実行時間 サブミリ秒 30 秒 (Viewer) / 30 秒 (Origin)
最大メモリ 2 MB 128 〜 10,240 MB
最大コードサイズ 10 KB 50 MB
ネットワークアクセス 不可 (KVS は可)
料金 非常に安価 Functions より高い

今回は単純なユーザー認証のみの Basic認証を実装したいので、高速・低コストな CloudFront Functions で構築します。

*1: 利用可能な関数やAPIは以下のドキュメントを参照してください。

docs.aws.amazon.com

CloudFront KeyValueStore (KVS) とは

CloudFront KeyValueStore は、CloudFront Functions から参照できるグローバルなキーバリューストアです。

docs.aws.amazon.com

CloudFront Functions では他の AWS リソースとの連携ができないため、Lambda@Edge とは異なり AWS Secrets Manager などに認証情報を格納して参照することができませんでした。

KVS を使うことで、CloudFront Functions のコード内から認証情報を参照できるようになります。

KVS はグローバルリソースとして管理されており、CloudFront Functions の実行環境から API 経由でアクセスできます。Basic認証のユーザー名とパスワードを KVS に格納して、関数コード内で参照する構成を取ることで、認証情報をコードにハードコードせずに管理できます。

【重要ポイント!】

  • KVS を利用するには、CloudFront Functions のランタイムを cloudfront-js-2.0 に設定する必要があります。

構築手順

それでは、実際に構築してみましょう!

手順 1: CloudFront + S3 の配信構成を作成する

まず、Basic認証を適用する対象となる CloudFront + S3 の配信構成を作成します。既に構成がある場合はこの手順をスキップしてください。

1-1. S3 バケットを作成する

まずは、コンテンツの格納先となる S3 バケットを作成します。

S3 コンソールより、「バケットを作成」 をクリックし、以下のようにバケット名を入力して作成してください。

項目 入力例 役割
バケット名前空間 アカウントのリージョナル名前空間 自動的にS3バケット名にアカウント一意な接尾辞が付与されます
バケット名の接頭辞 basic-auth-demo-bucket バケット名を接頭辞として指定します

リージョナル名前空間の設定(アカウント番号はマスク)

【ポイント!】

  • 2026年3月にリージョナル名前空間という機能が S3 に追加されました。これにより、自動的にアカウント一意な接尾辞がバケット名に付与されるため、他のユーザーや他のリージョンとバケット名が衝突しにくい命名が可能になりました。
  • -<アカウント番号>-<リージョン名>-an の形式で追加されます。
  • コンソールにも記載がありますが、接尾辞含めたバケット名は全体で 63 文字以内である必要があります。およそ30文字程度の接尾辞が付与されるため、接頭辞は30文字程度に抑えることを推奨します。

aws.amazon.com

1-2. テスト用の index.html をアップロードする

CloudFrontからアクセスしたときに表示するコンテンツを S3 にアップロードします。

  1. 以下の内容で index.html を作成
<!DOCTYPE html>
<html lang="ja">
<head><meta charset="UTF-8"><title>Basic Auth Demo</title></head>
<body><h1>認証成功!</h1><p>CloudFront Functions による Basic 認証を通過しました。</p></body>
</html>
  1. S3 コンソールで先ほど作成したバケットを選択
  2. ドラッグアンドドロップなどで、S3 バケットにアップロード

1-3. CloudFront Distribution を作成する

CloudFront + S3 の配信構成を作成します。オリジンアクセスは OAC で設定し、Viewer Request に CloudFront Functions を関連付けるための準備をします。

CloudFront コンソールより、「Distribution を作成」 をクリックし、以下のように設定してください。

項目 入力例 役割
Choose a plan Pay as you go 料金プラン
Distribution name basic-auth-demo-distribution Distribution の名前
Description basic-auth-demo-distribution Distribution の説明
Origin type Amazon S3 オリジンとするリソースの種類
Origin basic-auth-demo-bucket-<接尾辞> オリジンとして指定する S3 バケット
Allow private S3 bucket access to CloudFront チェックする CloudFrontからアクセスできるようにS3の変更を許可する
AWS WAF 任意 AWS WAF によるディストリビューションの保護
本番環境など保護が必要な場合は有効にしてください

【ポイント!】

  • Description は任意ですが、後ほどディストリビューション選択時に表示されるので入力することを推奨します。
  • S3のOrigin Access Control (OAC) を有効にすることで、CloudFront 以外からの S3 へのアクセスをブロックできます。CloudFrontのオリジン登録時に「Allow private S3 bucket access to CloudFront」にチェックを入れると、OAC の設定も自動で行われるため、S3バケットポリシーでCloudFrontからのアクセスのみを許可する構成が簡単に実現できます。
  • WAF は任意ですが、Basic認証の前段で悪意のあるリクエストをブロックできるため、本番環境などセキュリティが重要な場合は有効にすることを推奨します。

1-4. index.html をデフォルトで表示するように設定する

CloudFront が S3 の index.html をデフォルトで表示するように設定します。

この設定をしない場合は、CloudFront のルート URL にアクセスしたときに S3 を直接参照する(ListBucket)ようにふるまいます。 手順1-3 にて自動設定されたOACでは、S3バケットへのGetObjectリクエストのみを許可するポリシーが適用されます。 このため、ListBucket のリクエストはアクセス許可されず、403 エラーになります。

  1. CloudFront コンソールで対象の Distribution を選択
  2. 「一般」 タブを選択
  3. 「編集」ボタンを選択
  4. 以下の設定を行う
項目 入力例 役割
Default root object index.html デフォルトで表示するオブジェクト

1-5. 動作確認

Distribution のデプロイが完了するまで数分待ちます。

Webブラウザで CloudFront のドメイン名にアクセスして、以下のような画面が表示されれば、CloudFront + S3 の配信構成は完成です。

S3にホストされたページ

手順 2: KeyValueStore を作成する

まず、認証情報を格納する KVS を作成します。

  1. CloudFront コンソールを開く
  2. 左ペインから 「関数」を選択
  3. 「KeyValueStore」タブを開く
  4. 「Create KeyValueStore」ボタンをクリック
  5. 以下の設定を行う
項目 入力例 役割
Name basic-auth-kvs KeyValueStore の名前

手順 3: KVS に認証情報を登録する

KVS に Basic認証で使うユーザー名とパスワードを登録します。ユーザー名をキー、パスワードを値として格納します。

  1. 「Key value pairs」セクションの「Add key value pairs」ボタンを選択
  2. 「Add pair」ボタンを選択
  3. 以下の設定を行う
項目 入力例 役割
Key user KeyValueStore のキー
Value password KeyValueStore の値
任意の値を設定してください
  1. 「Save changes」ボタンを選択して保存

作成したKVS

【注意!】

  • 本記事ではデモのためパスワードを平文で KVS に格納していますが、本番環境では パスワードをハッシュ化して格納 することを推奨します。CloudFront Functions の JavaScript runtime 2.0 には crypto モジュール(sha256 対応)が含まれているため、関数内でハッシュ比較が可能です。

手順 4: CloudFront Functions を作成する

Basic認証を行う CloudFront Functions を作成します。

4-1. マネジメントコンソールで関数を作成

  1. CloudFront コンソールの左ペインから 「関数」を選択
  2. 「関数を作成」をクリック
  3. 以下の設定を行う
項目 入力例 役割
名前 basic-auth 関数名
Runtime cloudfront-js-2.0 実行ランタイム
  1. 「関数を作成」をクリック

【重要ポイント!】

  • ランタイムは必ず cloudfront-js-2.0 を選択してください。デフォルトの cloudfront-js-1.0 では KVS にアクセスできません。

4-2. 関数と KVS の関連付け

  1. 「Associate KeyValueStore」 項目から「Associate existing KeyValueStore」ボタンをクリックして、手順 2 で作成した KVS を選択
  2. 「Associate KeyValueStore」ボタンをクリックして関連付ける
  3. KVS 名の下に KVS ID が表示されるので控えておく(後で関数コードに貼り付ける)

4-3. 関数コードの編集

  1. 「関数コード」 セクションで、下記のコードを貼り付け
  2. コード内の <KVS_ID> を先ほど控えた KVS ID に置き換える
  3. 「変更を保存」をクリック

関数コード

import cf from 'cloudfront';

const kvsId = '<KVS_ID>';
const kvs = cf.kvs(kvsId);

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

  // Authorization ヘッダがない、または Basic でない場合は 401
  if (!headers.authorization || headers.authorization.value.indexOf('Basic ') !== 0) {
    return __unauthorized();
  }

  // Base64 デコードしてユーザー名・パスワードを分離
  // ※公式ドキュメントでは Buffer.from(str, 'base64url') が使用されています
  const decoded = atob(headers.authorization.value.slice(6));
  const parts = decoded.split(':');
  const username = parts[0];
  const password = parts.slice(1).join(':');

  // KVS からユーザー名をキーにしてパスワードを取得
  let expected;
  try {
    expected = await kvs.get(username);
  } catch (e) {
    return __unauthorized();
  }

  if (password !== expected) {
    return __unauthorized();
  }
  return request;
}

function __unauthorized() {
  return {
    statusCode: 401,
    statusDescription: 'Unauthorized',
    headers: {
      'www-authenticate': { value: 'Basic realm="Restricted"' },
    },
  };
}

【ポイント!】

  • import cf from 'cloudfront' は CloudFront Functions で利用できる専用のモジュールです
  • kvs.get(username) で KVS からユーザー名をキーにしてパスワードを取得しています
  • Base64 デコードには atob() を使用しています。なお、公式ドキュメントでは JavaScript runtime 2.0 で利用可能な Buffer モジュール を用いた Buffer.from(str, 'base64url') が紹介されています

docs.aws.amazon.com

CloudFront Functions途中経過(KVSの関連付け・コードの貼り付け)

4-4. 関数を発行する

保存しただけでは関数はまだ使えません。「発行」タブ から 「関数を発行」 をクリックして、関数を発行してください。

手順 5: CloudFront Distribution に関連付ける

作成した CloudFront Functions を Distribution の Viewer Request に関連付けます。

  1. 先ほどと同様に「発行」タブを選択
  2. 「関連付けられているディストリビューション」項目で「関連付けを追加」を選択
  3. 以下の設定を行う
項目 役割
ディストリビューション basic-auth-demo-distribution 関連付けるディストリビューション
イベントタイプ Viewer Request 関連付けるイベントタイプ
キャッシュビヘイビア Default(*) 関連付けるキャッシュビヘイビア
  1. 「関連付けを追加」 をクリック

Distribution のデプロイが完了するまで数分待ちます。ステータスが 「デプロイ済み」 になれば完了です。

CloudFront Functionsの設定完了(ディストリビューションとの関連付け)

動作確認

構築が完了したら、動作を確認してみましょう!

認証なしでアクセス

Webブラウザで CloudFront のドメイン名にアクセスすると、Basic認証のダイアログが表示されるはずです。認証なしでアクセスした場合は、CloudFront Functions の __unauthorized() が返す 401 エラーになります。

ブラウザの認証画面

認証失敗

正しい認証情報でアクセス(200 が返る)

先ほど、CloudFront KeyValueStore に登録したユーザー名とパスワードを使ってアクセスしてみましょう。

S3にホストされたページ

うまく表示されましたか? これで Basic認証が正しく動いていることが確認できました。

認証情報の変更方法

パスワードを変更したい場合は、KVS の値を更新するだけで次のリクエストより反映されます。

  1. CloudFront コンソールを開く
  2. 左ペインから 「関数」を選択
  3. 「KeyValueStore」タブを開く
  4. 対象の KVS を選択
  5. 「Key value pairs」セクションで、「Edit」ボタンを選択
  6. 対象のキーの値を新しいパスワードに変更して「Save Changes」ボタンを選択

KVSに格納された値の変更画面

(おまけ)CloudFront Functions でログを出力する

CloudFront Functions でも Lambda@Edge と同様に、Amazon CloudWatch Logs にログを出力することができます。 /aws/cloudfront/functions/<関数名> というロググループに出力されます。

注意点として、ロググループは自動的に作成されず、console.log() 等で出力を行って初めてロググループとログストリームが作成されます。 また、Lambda@Edge とは異なり、どのエッジロケーションからアクセスしてもus-east-1(バージニア北部)リージョンの CloudWatch Logs に出力されます。

関数にログ出力を追加する

  1. CloudFront コンソールを開く
  2. 左ペインから 「関数」を選択
  3. 対象の関数を選択
  4. 「関数コード」 セクションで、下記のようにログを出力するコードを追加
//
// ~略~
//

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

  // ログを出力
  console.log("Start Basic Authentication");

//
// ~略~
//
  1. 「変更を保存」をクリック
  2. 「発行」タブ から 「関数を発行」 をクリックして、関数を発行。

プライベートブラウジングモードなどで CloudFront のドメイン名にアクセスして、Basic認証のダイアログが表示されることを確認します。

【ポイント!】

  • 関数を保存しただけではログは出力されません。必ず「発行」タブ から 「関数を発行」 をクリックして、関数を発行してください。

CloudWatch Logs でログを確認する

  1. CloudWatch コンソールを開く
  2. 左ペインから 「ログ管理」を選択
  3. 「ロググループ」から、/aws/cloudfront/functions/<関数名> を選択

ロググループ

  1. ログストリームを選択して、ログを確認する

このように、先ほどCloudFront Functions で出力設定したログが CloudWatch Logs に表示されます。

ログ

【ポイント!】

  • CloudFront Functions で出力したログは、Lambda@Edge と異なり、us-east-1(バージニア北部)リージョンの CloudWatch Logs に出力されます。

【注意!】

  • ログは 10 KB で切り詰め られます。大量のログ出力を行うと途中で切れる可能性があります。
  • ログ配信は ベストエフォート です。すべてのリクエストのログが記録される保証はなく、完全なアクセス記録としては利用できないことに注意してください。

docs.aws.amazon.com

docs.aws.amazon.com

まとめ

Basic認証の実装方法として、CloudFront Functions と CloudFront KeyValueStore を組み合わせる方法を紹介しました。

この方法は、Lambda@Edge と比べて軽量・低コストで、認証情報の管理もコードから切り離せるため、S3 + CloudFront の静的コンテンツ配信に手軽にアクセス制限を追加したい場合に最適です。

  1. CloudFront Functions で Basic認証を実装できる

    • Viewer Request イベントで Authorization ヘッダを検証
    • Lambda@Edge より軽量・低コスト・低レイテンシ
  2. CloudFront KeyValueStore で認証情報を管理

    • コードに認証情報をハードコードしない
    • KVS の更新は次のリクエストから反映、デプロイ不要でパスワード変更可能
  3. 注意点

    • CloudFront Functions の関数コードサイズ上限は 10 KB(ライブラリ含む)
    • KVS は JavaScript 2.0 ランタイムでのみ利用可能
    • 関数の「発行」を忘れずに
  4. CloudFront Functions でも CloudWatch Logs にログ出力可能

    • console.log() でログを出力
    • ロググループは /aws/cloudfront/functions/<関数名> に作成される

この方法を活用することで、S3 + CloudFront の静的コンテンツ配信に手軽にアクセス制限を追加できます。

最後までお読みいただき、ありがとうございました!

圡井一磨(執筆記事の一覧)

23年度新卒入社しました。最近は自炊にはまっています。アパートのキッチンが狭くて困ってます。