CloudFront Functions で JWT を検証することはできますか

CloudFront Functions で JWT を検証することはできますか

Clock Icon2025.03.04

困っていた内容

CloudFront Functions で JWT を検証することはできますか。

どう対応すればいいの?

結論から言えば、 HMAC で署名された JWT であれば検証することが可能ですが、 RSA で署名された JWT を検証することは困難です。

理由についてですが、 CloudFront Functions には以下のような非常に厳しい制約があり、 RSA で署名された JWT を検証する計算リソースが不十分なためです。どうしても CDN レイヤーにおいて RSA で署名された JWT の検証を実行したい場合には、 Lambda@Edge の利用 をご検討ください。

  • 関数のソースコードサイズ: 10KB 以内
  • 最大メモリ使用量: 2MB 以内
  • 実行時間: 1 ミリ秒以内
  • 利用可能なモジュール: ビルトインモジュールのみ。
    • HMAC 署名の検証用のモジュールは提供されていますが、 RSA 用は提供されていません。

やってみた

というわけで、実際に CloudFront Functions を利用して HMAC で署名された JWT を検証したいと思います。

構成

書くほど複雑なものでもないですが、構成図は以下のようになります。
ユーザーがアクセスすると、 CloudFront ディストリビューションのビューワーリクエストに紐づけられた CloudFront 関数が実行されます。関数内では KeyValueStore に保存された秘密鍵を取得し、これを用いて ユーザーから渡された JWT を検証します。検証が成功した場合にはオリジンに指定した S3 バケットにリクエストを通し、失敗した場合には 401 エラーを返すようにします。

cloudfront-functions-jwt

ソースコード

ソースコードはサンプルコードが公式ドキュメントに記載されているので、これをそのまま利用してみます。

あまり機能的にカスタマイズの余地がないので、以下のポイントをおさえつつ、必要に応じて JWT ペイロードの検証を追加していただくと良いと思います。

  • 署名の検証にはビルトインモジュールである Crypto を利用する
  • HMAC 署名の秘密鍵は KeyValueStore から取得する
  • nbf フィールドと exp フィールドを確認し、 JWT が有効期限内であることを確認する

その他の設定

事前に、CloudFront ディストリビューションの向き先として S3 バケットを用意し、 index.html に適当な内容を記入しておきます。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>CloudFront Functions JWT検証テスト</title></head>
<body>
  <h1>CloudFront Functions JWT検証テスト</h1>
  <p>検証成功😎</p>
</body>
</html>

次に CloudFront ディストリビューションを作成します。オリジンを先程作成した S3 バケットとします。 OAC は有効化した上で、バケットポリシーを先程の S3 バケットにも反映しておきましょう。
それ以外の項目はスキップしてディストリビューションを作成します。

スクリーンショット 2025-03-03 17.50.43

次に CloudFront Functions に関数を作成します。
後ほど秘密鍵を保存しておくための KeyValueStore を作成しますが、これを利用するにはランタイムバージョンを 2.0 に指定しておく必要があります。

スクリーンショット 2025-03-03 17.58.55

ソースコードを関数に設定したら、関数を発行します。

スクリーンショット 2025-03-04 10.58.28

スクリーンショット 2025-03-04 10.58.40

さらに CloudFront KeyValueStore を作成します。
S3 上にアップロードした JSON から値を投入することもできますが、マネジメントコンソールからも投入できるのでスルーします。

スクリーンショット 2025-03-03 18.02.10

KeyValueStore に HMAC 署名の秘密鍵を投入します。 Key の値は先程のソースコードで指定したキー名と一致するようにしましょう。

スクリーンショット 2025-03-03 18.04.46

あとは作成した KeyValueStore を関数に関連付けします。

スクリーンショット 2025-03-04 11.00.55

最後に CloudFront ディストリビューションのビヘイビアを編集し、ビューワーリクエストで先程作成した CloudFront Functions の関数を指定します。特定のパス配下でのみ実行したい場合には、適切なパスパターンに絞って指定しましょう。

動作確認

CloudFront ディストリビューションのデプロイが完了したら、 S3 バケットにアップロードした index.html に CloudFront 経由でアクセスしてみます。

まずは JWT なしでアクセスしてみます。すると、関数内で指定したように 401 エラーが返されることが確認できます。

https://dxxxxxxxxxxxxx.cloudfront.net/index.html

スクリーンショット 2025-03-04 11.04.25

次に、 JWT ありでアクセスしてみます。 AWS から提供されているサンプルコードに JWT を生成するシェルが提供されているので、これを実行して生成された JWT を利用してアクセスしてみます。

./generate-jwt.sh
eyJh...ciOiAiSFMyNTYiLCJ0eXAiOiAiSldUIn0.eyJz...IjogIjEyMzQ1Njc4OTAiLCJuYW1lIjogIkpvaG4gRG9lIiwiaWF0IjogMTUxNjIzOTAyMiwgIm5iZiIgOiAxNjE2MjM5MzIsImV4cCIgOjE3NDA5ODU5MTggfQ.oEWz_-aBcV...1h-0n91h0

https://dxxxxxxxxxxxxx.cloudfront.net/index.html?jwt=eyJh...ciOiAiSFMyNTYiLCJ0eXAiOiAiSldUIn0.eyJz...IjogIjEyMzQ1Njc4OTAiLCJuYW1lIjogIkpvaG4gRG9lIiwiaWF0IjogMTUxNjIzOTAyMiwgIm5iZiIgOiAxNjE2MjM5MzIsImV4cCIgOjE3NDA5ODU5MTggfQ.oEWz_-aBcV...1h-0n91h0

スクリーンショット 2025-03-04 11.06.55

無事に JWT ありの場合でのみ index.html にアクセスできることが確認できました。

あとは補足情報ですが、 CloudFront Functions の関数内に console.log で出力した内容は、 CloudWatch Logs の /aws/cloudfront/function/${関数名}/ ロググループで確認することができます。

スクリーンショット 2025-03-04 11.12.55

参考文献

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.