403 エラーが返ってきた時に特定 URL にリダイレクトする Lambda@Edge を試してみた

403 エラーが返ってきた時に特定 URL にリダイレクトする Lambda@Edge を試してみた

Clock Icon2025.03.25

こんにちは、岩城です。

CloudFront を利用している環境で、オリジンから 403 エラーがレスポンスされた場合、指定した URL にリダイレクトしたいことがありました。

試してみた結果を共有します。

まとめ

  • CloudFront Functions はオリジンが 400 以上のエラーを返した場合、実行されない
  • Lambda@Edge は 400 以上のエラーを返されても Lambda 関数を実行できる
  • Lambda@Edge を使用してオリジンが 403 エラーを返した場合、指定したURLにリダイレクト Lambda 関数を実行させる

CloudFront Functions と Lambda@Edge の違い

CloudFront Functions と Lambda@Edge はどちらも CloudFront のイベントに応じてコードを実行できます。

CloudFront Functions は、軽量で実行時間の短い関数に最適ですが、Lambda@Edge は以下のユースケースに最適とされています[1]

  • 完了までに数ミリ秒以上かかる関数
  • 調整可能な CPU またはメモリを必要とする機能
  • サードパーティライブラリに依存する関数 (他の AWS のサービスとの統合のため、AWS SDK を含む)
  • 外部サービスを使用して処理するために、ネットワークアクセスを必要とする関数
  • ファイルシステムへのアクセスまたは HTTP リクエストの本文へのアクセスを必要とする関数

さらに、CloudFront Functions は、オリジンが 400 以上の HTTP エラーを返した場合、CloudFront Functions は実行されません。

ということで、本エントリではオリジンが 403 を返したときにリダイレクトさせたかったため、Lambda@Edge を採用しました。

やってみた

構成図

vscode-drop-1742805172620-jfaimhvmatg.png

CloudFront と S3 の静的ウェブサイトホスティングを利用します。

Origin response で 403 エラーが返ってきた時に、Lambda@Edge で特定の URL にリダイレクトさせます。

CloudFront と S3 の静的ウェブサイトホスティング

CloudFront と S3 の静的ウェブサイトホスティングは、特別なことは設定しておらず、基本的にはデフォルトの設定です。

大した設定ではないのでさらっと紹介します。

S3 の静的ウェブサイトホスティング
S3 バケットを作成して静的ウェブサイトホスティングを有効にしました。

vscode-drop-1742800640198-r5s3nly2rbk.png

作成した S3 バケットのルートに以下の index.html をアップロードしました。
favicon 起因の 403 エラーを避けるため、favicon.ico を定義しています。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" type="image/x-icon" href="https://dev.classmethod.jp/favicon.ico">
  </head>

  <body>
    <h1>
      こちらはIndex.html
    </h1>
  </body>
</html>

CloudFront
オリジンに上で作成・設定しておいた S3 バケットを指定します。

vscode-drop-1742800677017-xxhgc5ntv7c.png

ビヘイビアも基本的にはデフォルト設定ですが、検証を容易にするためにキャッシュは無効化しておきました。

vscode-drop-1742800734170-qbw0oxvl2e.png

Lambda@Edge

まず Lambda@Edge で使用する実行ロールを作成します。

実行ロールは 公式ドキュメント を参考に以下のとおり設定しました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:*:*:*"
            ]
        }
    ]
}

信頼ポリシーは以下のとおりです。edgelambda.amazonaws.comを追加しないと権限不足になります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "edgelambda.amazonaws.com",
                    "lambda.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

つぎに、Lambda 関数を作成します。

CloudFront のリージョンに合わせる必要があるため、バージニア北部で以下のように設定しました。

vscode-drop-1742804236434-15pm4xn10dp.png

exports is not defined in ES module scope のエラーが発生するので、ファイル名を index.mjs から index.js に変更します。

vscode-drop-1742804254951-lsvxh0u5k1.png

コードはあくまで サンプル なので参考程度に考えてください。

'use strict';

exports.handler = (event, context, callback) => {
    const response = event.Records[0].cf.response;
    const redirectUrl = `<リダイレクト先の URL>`;
    
    if (response.status == 403) {
        response.status = 302;
        response.statusDescription = 'Found';
        response.headers['location'] = [{ 'value': redirectUrl }];
    }

    callback(null, response);
};

アクションから Lambda@Edge へのデプロイ を行います。

CloudFront イベントはオリジンレスポンスを設定します。

vscode-drop-1742804764690-86rzjxwgkyg.png

デプロイすると CloudFront に反映されます。

vscode-drop-1742805048323-9zmumizwr1u.png

動作確認

存在しない URL にアクセスしオリジンから 403 エラーが返り、Lambda@Edge で設定したとおり、ステータスコード 302 Found が返り、指定した URL にリダイレクトされることを確認できました。

vscode-drop-1742864009932-l0ittz28qp.png

おわりに

本エントリを執筆する動機は、403 エラーが返ってきた時にエラーページを表示させたくなく、403 エラーが返ってきた時にトップページへのリダイレクトを想定するものでした。

favicon の未設定含めて、403 エラーが返ってきたら何でもリダイレクトされてしまうので副作用は強めかも知れません。

本エントリがどなたかのお役に立てれば幸いです。

脚注
  1. すべてのエッジ機能に対する制限 - Amazon CloudFront ↩︎

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.