Amazon CloudFront KeyValueStoreを活用した記事のリリース制御

この記事はJapan AWS Ambassador Advent Calendar 2023の12/22付記事となります。

こんにちは、SCSKの木澤です。

昨日の記事は早川さんによる「JAWS DAYS 2024 “LEAP BEYOND”~ラーニング・コミュニティで得られるもの~」でした。
早川さんは2024/3/2に開催されるJAWS DAYS 2024の実行委員長を担当されます。10月に福岡で開催されたJAWS Festa 2023で発表があり大変驚きましたが技術力/実行力とも兼ね備える才色兼備なアンバサダーです!

私はAWS Ambassadorを拝命して3年目になりました。
AWSサービスの進化と共に、インフラエンジニア出身の私としては徐々に肩身が狭くなることを感じつつも、今後とも各社の優秀な方々と交流し刺激(プレッシャー)を頂くことを楽しみにしています。私自身としても、私ができる範囲でのアウトプットを続けて行ければと思います。

さて、今回は最近注目しているアップデートとして、Amazon CloudFront KeyValueStoreの活用について紹介したいと思います。

公式ブログはこちら

Amazon CloudFrontでのエッジコンピューティング

Amazon CloudFrontとエッジ処理の概要

Amazon CloudFrontの特徴と概要については、以前当サイトにてご紹介しました。

Amazon CloudFrontとキャッシュ制御の基礎
CDNおよびAmazon CloudFrontの概要と、Webサイトにおけるキャッシュ制御の考え方、CloudFrontの設定方法まで解説をします。 Webサイトにおける基本的なCloudFront適用の考え方を一通り網羅しているかと思います。

Amazon CloudFrontはCDN(Contents Delivery Network)のサービスであり、極力ユーザの近くからに設置したキャッシュからWebコンテンツを配信することでサイトの高速表示とサーバの負荷軽減に貢献するサービスとなります。

CloudFrontの配信拠点をエッジロケーションと呼びます。
上記の記事を発信した際(2022年3月)には全世界で300以上と記載しておりましたが、約20ヶ月経過した現在では600以上と記載が変更されています。どんどんエッジロケーションは増えているようです。

特徴 - Amazon CloudFront | AWS
Amazon CloudFront のグローバルコンテンツ配信ネットワーク (CDN) の主な機能について説明します。Amazon CloudFront は、データ、動画、アプリケーション、および API をすべてデベロッパーにとって使いや...

さて折角エッジロケーションで一旦アクセスを受け付けるのであれば、以下のような処理をエッジ側で行いたいというニーズが発生することがあります。

  • 認証
  • URLリライト/リダイレクト
  • 応答コードのカスタマイズ
  • HTMLレンダリング処理/画像変換

これらの要求に対応するため、エッジロケーション内で処理を実装できるのが今回ご紹介するサービス群となります。

本記事内では一部、re:Invent 2023のワークショップで撮影した写真を利用しています

CloudFront FunctionsとLambda@Edgeの違い

CloudFront内で処理を行うサービスはCloudFront FunctionsとLambda@Edgeの2種類があります。
違いを表にまとめますと、以下のようになります。

サービス CloudFront Functions Lambda@Edge
ユースケース
  • 認証
  • HTTP応答コードのカスタマイズ
  • URLリライト/リダイレクト
  • サーバサイドレンダリング
  • 応答のパーソナライズ
  • ボットアクセスの排除
言語 JavaScript Node.js
Python
ネットワークアクセス
不可
スケール 10,000,000リクエスト/秒 10,000リクエスト/秒/リージョン
実行時間の制限 数ミリ秒 5秒 (ビューアーアクセス側処理)
30秒 (オリジンアクセス側処理) 
関数の容量制限 10KB 250MB
コスト $0.1/100万回 $0.6/100万回

ユースケースと適用場所の違いはこの図が解りやすいかと思います。
私の理解は下記の通りです。

  • 限定的な用途だが大量処理でき安価な CloudFront Functions
  • リージョン内の他AWSサービスと連携して高度な処理が出来る Lambda@Edge

制限事項等、仕様について詳しくは公式ページをご覧下さい

 

Amazon CloudFront KeyValueStoreについて

さて今回発表されたKeyValueStoreですが、CloudFront Functionと連携し利用できる簡易データベースとなります。

従来、CloudFront Functionsはネットワークアクセスができないため他のAWSサービスと連携できず利用用途が限られていましたが、本機能を利用することで関数の容量制限(10KB)を超えたデータを持てるようになるため、認証等CloudFront Functionsの用途が格段に拡大するアップデートかと思います。

ビューアーアクセス(ユーザーリクエストへの応答)の制御にはCloudFront Functions+KeyValue Store、オリジンアクセスを高度化しコンテンツ生成のカスタマイズを行いたい向きにはLambda@Edgeと使い分けるのがベストプラクティスと考えられます。

本Key-Value StoreへのメンテナンスはマネジメントコンソールやAWS CLIで可能な他、APIアクセスによる値の変更も可能ですので、リージョン内のAWSサービスと連携した自動制御を行うことができます。

なお、本KeyValue Storeの価格は以下の通りです。

  • CloudFront Functionsからの読み取り:$0.03/100万アクセス
  • APIアクセス:$1.0/1000アクセス

 

実装してみた

さて今回はプレスリリース等、期日が来るまで発信してはならないユースケースを想定し、特定URLにアクセスがあった際にURLリライトによる転送を行うといった実装を考えてみます。

KeyValue Storeの作成

CloudFrontのコンソール左側のメニューから「関数」を選択し「KeyValueStores」のタブをクリックします。

KeyValueStoreの名前を入力し作成します。
この際、事前にJSON形式のファイルをS3に作成しておき値を直接読み込むこともできます。

作成できました。
続いて値を入力します。

キーと値を入力し保存します。
今回は値が「Rewrite」となっているURIへのアクセスを書き換えることにします。

CloudFront Functionsの作成

続けて作成したKeyValueStoreを用いてアクセス制御する関数を実装します。

Functionsタブにて「関数を作成」ボタンをクリックします。

関数の名前を入力します。
ランタイムはcloudfront-js-2.0である必要があるようです。

関数のひな形が作成できました。
KeyValueStoreの紐付けを行います。

作成したKeyValueStoreを指定します。

紐付けが完了するとサンプルコードが表示されます。(優しいですね!)
KeyValueStoreのIDが埋め込まれているので、これを活用してコーディングを開始すると良いかと思います。

今回は以下のようなコードにしました。
単純にKeyValueStoreに値「Rewrite」として登録があるURIへのアクセスがあった際に特定URIにリライトする処理です。

import cf from 'cloudfront';

const kvsId = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
const rewriteURI = '/';

// This fails if the key value store is not associated with the function
const kvsHandle = cf.kvs(kvsId);

async function handler(event) {
    const request = event.request;
    const uri = request.uri;
    let value = "Not found" // Default value
    try {
        value = await kvsHandle.get(uri);
        if(value=='Rewrite'){
            // URL rewrite to another path if the key is "Rewrite"
            console.log(`${request.uri} -> ${rewriteURI}`)
            request.uri = rewriteURI;
        } else {
            // No change to the pathname if the key is another value
            console.log(`${request.uri} | ${value}`);
        }
    } catch (err) {
        // No change to the pathname if the key is not found
        console.log(`${request.uri} | ${err}`);
    }

    return request;
}

コーディング後、コンソール上からテストを行うことも可能です。
URIに応じた動作を確認でき、助かります。

テストで動作を確認したら、発行しましょう。

CloudFrontディストリビューションへの割り当て

作成した関数をCloudFrontのディストリビューション(ビヘイビア)に紐付けます。
これにより、特定のビヘイビアに対してアクセスがあった際にCloudFront Functionsが反応して動作するようになります。

設定はディストリビューション側、関数側両方から行うことが出来ますが、今回は関数側から行います。
ディストリビューションとの「関連付けの追加」をクリックします。

関連付けるディストリビューション、イベントタイプ、ビヘイビアを選択します。

これで設定完了です。
ディストリビューション側の設定画面でも、作成したCloudFront Functionsと紐付いていることを確認できます。

ビヘイビアの選択後にCloudFront Functionsが実行される仕様のため、他ビヘイビアに跨がるURIへのリライトはできません。別オリジンに静的ページを設置しているようなケースではご注意ください。

動作確認

さて、以上で実装が完了しました。
ディストリビューションの配下の指定したURIにアクセスした際、特定のページ(上記コードの場合はトップページ)が表示されるようになっているはずです。

このコードを応用すれば「特定IPアドレスからアクセスがあった際は表示するが、その他のアドレスには表示しない」等の設定も容易に出来るはずです。柔軟にカスタマイズできて良いですね。

なお、CloudFront Functionsの動作ログは、us-east-1リージョンのCloudWatch Logs(ロググループ:/aws/cloudfront/function/関数名)に出力されます。
デバッグの際はこちらを参照すると良いでしょう。

 

まとめ

従来からAmazon CloudFrontについては私の好きなサービスの1つですが、CloudFront FunctionsやLambda@Edgeは必要性に駆られず、今まで触っていませんでした。

今回のアップデートを機にCloudFront Functionsを触ってみましたが、簡単に実装でき面白かったですね。
今後は色々なユースケースに積極的に活用していこうと思います。(Lambda@Edgeも)
皆さんのご参考にもなれば幸いです。

さて明日のJapan AWS Ambassador Advent Calendar 2023は、AmbassadorやJAWS-UGのイベントで今年も頻繁に交流させていただいた、EQに詳しいフェンリル柴田さんの投稿です! お楽しみに。

タイトルとURLをコピーしました