0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[実践]CloudFront + Lambda@Edgeによるドメインリダイレクト

Posted at

画像3.png

概要

こちらの記事でAWSサービスを使ったドメインリダイレクト手法についてまとめました。
その中でCloudFront関連の方法を試していこうと思い記事にします。
今回は「CloudFront+Lambda@Edge」編です。

実践

構成図

  • CloudFrontに代替ドメインでアクセス
  • ビューワーリクエストに対してLambda@Edgeで処理(後述)
  • 特定のPathの場合にリダイレクト先のALBにリクエストを転送

画像5.png

デプロイ

環境はGitHubで公開しています。
各コードとデプロイ方法を用意してますのでお試しください。

設定値

各ポイントとなる設定値を見ていきます。

CloudFront

ディストリビューションに代替ドメインを設定

画像1.png

オリジンはS3のリージョナルエンドポイント(REST API Endpoint)

画像2.png

S3オリジンにOAC(Origin Access Control)を設定

画像3.png

デフォルトビヘイビアのビューワーリクエストにLambda@Edgeを適用

画像4.png

Lambda@Edge

コード

リクエストのURI(Path)が「/test1/」or「/test2/」の場合に、ALBに設定した独自ドメインにリダイレクトさせるコードです。

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    request_path = request['uri']

    # Pathチェック
    if request_path == '/test1/':
        redirect_url = 'https://リダイレクト先FQDN/test1/'
    elif request_path == '/test2/':
        redirect_url = 'https://リダイレクト先FQDN/test2/'
    else:
        # マッチしない場合は元のリクエストを返す
        return request

    # リダイレクトレスポンス
    response = {
        'status': '301',
        'statusDescription': 'MovedPermanently',
        'headers': {
            'location': [{
                'key': 'Location',
                'value': redirect_url
            }]
        }
    }

    return response

イベントは公式ドキュメントを参考にしています。

IAMロール

信頼ポリシーは以下の通りです。

信頼ポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": [
                    "lambda.amazonaws.com",
                    "edgelambda.amazonaws.com"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
IAMポリシーではCloudWatch Logs関連の許可を付与
  • Lambda@Edge用のLambda関数はバージニア北部リージョンで作成する必要がありますが、実行時はリクエスト元の最寄りリージョン別エッジキャッシュにレプリカが作成され実行されます
  • そのため、ロググループ作成許可のStatementではリージョンを*にしています
  • Lambda@Edgeのロググループ名は/aws/lambda/us-east-1.関数名で作成されるため、
    ログイベントは該当のロググループに出力できるように許可しています
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCreateLogGroup",
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:*:AccountId:*"
        },
        {
            "Sid": "AllowPutLogEvents",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:AccoundId:log-group:/aws/lambda/us-east-1*"
        }
    ]
}

S3

バケットポリシーにCloudFront OACからのアクセス許可を追加
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::バケット名/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::アカウントID:distribution/ディストリビューションID"
                }
            }
        }
    ]
}

動作確認

まず、Lambda@Edgeコードの条件にマッチしないリクエストを呼び出してみます。
ディストリビューションに設定したデフォルトルートオブジェクト(S3バケットにホストしたindex.html)がレスポンスとして返ってきます。

$ curl -i https://ディストリビューション代替ドメイン/
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 316
Connection: keep-alive
x-amz-id-2: EvYdBiurBUqjXHMa0paHa/L+U+AwWgv5vIWT2sFbKV9mzIl+iirLDScFZ8QzMSSmROptIILLu3rP5Kr2mVGLsVuVcJNN8Xjnzw+h46KKf1A=
x-amz-request-id: FYHWE5MFR4EEV3HH
Date: Thu, 20 Mar 2025 15:54:46 GMT
Last-Modified: Thu, 20 Mar 2025 11:43:56 GMT
ETag: "0b51ba8caa5af4d214532a9912de1e23"
x-amz-server-side-encryption: AES256
Accept-Ranges: bytes
Server: AmazonS3
X-Cache: Miss from cloudfront
Via: 1.1 13c972ba4a9ffc82bb0bdabc148e3d20.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: KIX56-P1
X-Amz-Cf-Id: W_JjHiPfCH0riIOifgyVIJTClMWEotmlvo3kZLzGt_MF_rUp2DdyQg==

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>S3</title>
  </head>
  <body>
    <h1>S3 Default Page!</h1>
    <p>このページは S3 にホストされています。</p>
  </body>
</html>

続いて、Lambda@Edgeコードの条件分岐にマッチするリクエストを送信してみます。

$ curl -i -L https://ディストリビューション代替ドメイン/test1/
HTTP/1.1 301 MovedPermanently
Content-Length: 0
Connection: keep-alive
Server: CloudFront
Date: Thu, 20 Mar 2025 15:57:08 GMT
Location: https://リダイレクト先ドメイン/test1/
X-Cache: LambdaGeneratedResponse from cloudfront
Via: 1.1 a7d4728ae140bd74f2dfa727c541f5e6.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: KIX56-P1
X-Amz-Cf-Id: L2pFCzKmRqjXnoDiavY50-qP2ev3HibG7FP1SHztzKpDlQz-9DGKgg==

HTTP/1.1 200 OK
Date: Thu, 20 Mar 2025 15:57:08 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 232
Connection: keep-alive
Server: Apache/2.4.62 (Amazon Linux)
Last-Modified: Thu, 20 Mar 2025 11:13:29 GMT
ETag: "e8-630c43a3fe02c"
Accept-Ranges: bytes

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>EC2</title>
</head>
<body>
    <h1>Web Server Test1 Page!</h1>
</body>
</html>

まとめ

今回は「CloudFront+Lambda@Edge」を試してみました。
「CloudFront Functions」と比較し、より柔軟な処理を実装できる点はメリットだなと感じました。

参考資料

リファレンス

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?