[AWS] CloudFrontのオリジンを動的に変更する – Lambda@Edge + Node.js

CloudFrontで参照しているオリジンをLambda@Edgeで変更してみます。

今回はhttp://foo.example.comでアクセスされたら、CloudFrontがオリジンhttp://example.com/foo/へリクエストする設定をします。

正直なところあまり需要は無いと思いますがw この設定が生きてくるのは大量に同様の設定をしなければならない時ですね。設定が必要なドメインが2〜3個であればCloudFront側でディストリビューションを必要なだけ作成する方がわかりやすいです。

というわけで先ほどの例の「foo」の部分はどのような文字列が来ても対応可能なよう設定していきます。

基本的な設定の流れ

大きな流れは過去の記事とほぼ同じです。以下を参照ください。IAMの信頼関係などハマりどころも説明しています。 blog.katsubemakito.net

Cloud Front

代替ドメイン名 (CNAME)」は以下のようにワイルドカードを指定しています。

またCDNにキャッシュは一切しない設定にしておきます。

ACM

AWSの無料証明書(ACM)の方もワイルドカードドメインに指定しておきます。CloudFrontで利用するのでリージョンを「バージニア北部(us-east-1)」にしておくのをお忘れなく。

Route53

CloudFrontに独自ドメインを付ける際にレコード名の部分はこちらもワイルドカード(*)を指定しています。

これでサブドメインにどのような文字列が指定されたとしても、同じCloudFrontのディストリビューションにたどり着きます。

Lambda@Edge

コード

リクエストされた情報を参照し、それを元にオリジンを書き換えています。ここではオリジンはカスタムドメインが前提となっていますので、S3をHDD的に利用する場合は修正が必要です。

exports.handler = async (event, context, callback) => {
    const request = event.Records[0].cf.request

    if ( request.headers['host'] ) {
        const origin = 'example.com'    // 変更先のオリジン
        const host = request.headers.host[0].value           // foo.example.com
        const path = host.replace('.example.com', '')  // foo

        // オリジンを書き換える
        request.origin.custom.domainName = origin
        request.origin.custom.path = '/' + path
        request.headers['host'] = [
            {key:'host', value:origin}
        ]
    }

    return callback(null, request)
}

ちなみにrequest.origin.custom.pathで指定するパスはスラッシュで開始する必要があり、もし異なる場合は503エラーが返ってきます。また文字列の末尾にスラッシュを付けることもNGです。……いやその判定できるなら良い感じに動いてくれw

CloudWatch上のエラーは以下のように出力されます。

ERROR Validation error: The Lambda function returned an invalid origin configuration, the value of origin path is invalid, path must start with '/', received path : foo.

デプロイ

CloudFrontのイベントは「オリジンリクエス」を選択します。

参考ページ