Lambda@Edgeを利用してリダイレクトやフォワードする方法

Lambda@EdgeはLambdaをCloudFrontのエッジロケーションで実行するもので、CloudFrontで受けたアクセスに対して何かしらの処理を実行するのに安くて便利な方法です。

今回はLambda@Edgeを使ってリダイレクトやフォワードするための方法を紹介します。

リダイレクトやフォワードの為にわざわざApacheサーバーなどを用意しなくてよいですし、Lambdaを使うことで(常時サーバー立ち上げが必要ないので)非常に安く済みます

手段の一つとして覚えておき活用してもらえたら嬉しく思います。

今回紹介するアーキテクチャ
(クリックすると画像が拡大されます。)

本記事ではLambda@Edgeの基本的な構築の流れを1から解説しています。
既に知っている場合は飛ばしながら読んでください。

アーキテクチャ構築の流れ

さっそく構築手順を紹介していきます。
構築の流れは以下のようになります。

Lambda@Edge構築の流れ

1. CloudFrontを構築
  1-1. ダミーオリジンの作成
  1-2. CloudFrontの構築
2. Lambda@Edgeを構築
  2-1. Lambda@Edge用のIAM作成
  2-2. Lambdaの構築
  2-3. トリガーの設定

まず紹介する構築の流れではリダイレクト用のLambdaファンクションコードを紹介しますが、
フォワード用のソースコードやパスを任意で変えるためのソースコードなども後から紹介します。

Lambda@Edgeのアーキテクチャ構築の流れは変わらないので、Lambdaファンクションのコードを変えれば実行する処理を変えることができます。

また、Lambda@Edge構築のポイントは以下となります。このポイントだけでも押さえておくとよいと思います。

Lambda@Edge構築のポイント
  • Lambda@Edge用のIAMロールを作成し、信頼関係を追加する必要がある
  • Lambda@EdgeのLambdaファンクションはバージニア北部リージョンに作成する
  • Lambdaファンクションから特定のバージョンを発行してトリガー設定が必要になる
  • LambdaのトリガーをCloudFrontにすることでLambda@Edgeとなる

CloudFrontを作成

ダミーオリジンの作成

まずはCloudFrontを構築するためのダミーオリジン用のS3バケットを作成していきます。
CloudFrontは必ずオリジンを設定しなければならないため、オリジン用として空のS3バケットを用意しておけばOKです。

S3コンソール画面の「バケット」から「バケットを作成」をクリックします。

ダミーバケットの作成(1/2)
(クリックすると画像が拡大されます。)

バケット名」だけ入力し「バケットを作成」をクリックします。
バケットの各種設定はデフォルトから変更する必要はありません。

ダミーバケットの作成(2/2)
(クリックすると画像が拡大されます。)

CloudFrontの構築

ダミーバケットが作成出来たらCloudFrontの構築を行います。

CloudFrontコンソール画面の「ディストリビューション」から「ディストリビューションを作成」をクリックします。

CloudFrontの作成(1/2)
(クリックすると画像が拡大されます。)

オリジンドメイン」だけ先ほど作成したダミーバケットを指定し「ディストリビューションを作成」をクリックします。
CloudFrontの各種設定はデフォルトから変更する必要はありません。

CloudFrontの作成(2/2)
(クリックすると画像が拡大されます。)

ここまででLambda@Edgeを実行するCloudFrontが構築できました。

Lambda@Edgeを構築

実行用のCloudFrontができたので、続けてLambda@Edgeを構築していきます。

Lambda@Edge用のIAM作成

Lambda@Edgeでは通常のLambda用IAMロールから「信頼関係」などを変更したIAMロールを使用する必要があります

まずはLambda@Edge用のIAMロールを作成していきます。

IAMコンソール画面の「ロール」から「ロールを作成」をクリックします。

IAMロールの作成(1/6)
(クリックすると画像が拡大されます。)

信頼されたエンティティを選択では、「AWSのサービス」から「Lambda」を選択し、「次へ」をクリックします。

IAMロールの作成(2/6)
(クリックすると画像が拡大されます。)

許可を追加では、検索窓に「lambda」と入力し、「AWSLambdaRole」を選択して「次へ」をクリックします。

IAMロールの作成(3/6)
(クリックすると画像が拡大されます。)

名前、確認、および作成では、「Role名」を入力して「ロールを作成」をクリックします。

IAMロールの作成(4/6)
(クリックすると画像が拡大されます。)

このままではデフォルトのLambda用IAMロールと変わらないので、Lambda@Edge用に信頼関係を追加していきます。

IAMコンソール画面の「ロール」から先ほど作成したIAMロールを選択し、「信頼関係」タブの「信頼ポリシーを編集」をクリックします。

IAMロールの作成(5/6)
(クリックすると画像が拡大されます。)

信頼関係に「edgelambda.amazonaws.com」を追加してください。
追加する位置は以下のオレンジ箇所になります。

IAMロールの作成(6/6)
(クリックすると画像が拡大されます。)

ここまでで、Lambda@Edgeを実行できるIAMロールはできました。

ここからはCloudWatch Logsにログを出力できるようにさらにIAMポリシーを追加していきます。

IAMコンソール画面の「ポリシー」から「ポリシーを作成」をクリックします。

IAMポリシーの追加(1/5)
(クリックすると画像が拡大されます。)

IAMポリシー作成画面ではビジュアルエディタでサービスを「CloudWatch Logs」を選択し、アクションに「CreateLogGroup」、 「CreateLogStream」 、 「PutLogEvents」を追加します。
log-groupとlog-streamの対象を設定する必要があるので、「ARNの追加」から設定します。
log-groupは「Region:すべて」、「Log group name:すべて」とします。
log-streamは「Region:すべて」、「Log group name:すべて」 、「Log stream name:すべて」とします。
設定出来たら「次のステップ:タグ」をクリックします。

IAMポリシーの追加(2/5)
(クリックすると画像が拡大されます。)

タグは特に必要ないので「次のステップ:確認」をクリックします。

IAMポリシーの追加(3/5)
(クリックすると画像が拡大されます。)

名前」を任意で入力し「ポリシーの作成」をクリックします。

IAMポリシーの追加(4/5)
(クリックすると画像が拡大されます。)

IAMポリシーを作成出来たら、IAMコンソール画面の「ロール」から作成したLambda@Edge用ロールを選択して「許可」の「アクセス許可を追加」から先ほど作成した「ポリシーをアタッチ」します。

IAMポリシーの追加(5/5)
(クリックすると画像が拡大されます。)

ここまでで、Lambda@Edgeを実行するためのIAMロール作成が完了しました。

Lambdaの構築

ここまで来たらいよいよLambdaを構築していきます。

Lambda@Edgeを作成するうえでのポイントはLambdaを「バージニア北部リージョンに構築すること」です。
CloudFrontはグローバルリージョンに作成されるのでCloudFrontをトリガーにできる設定できるのはバージニア北部リージョンのLambdaのみです。

Lambdaコンソール画面の「関数」から「バージニア北部リージョン」を選択したうえで「関数の作成」をクリックします。

Lambdaの構築(1/3)
(クリックすると画像が拡大されます。)

関数名」を任意で入力し、ランタイムを「Python3.8」にします。
デフォルトの実行ロールの変更から「既存のロールを使用する」を選択し、「作成したIAMロール」を入力して「関数の作成」をクリックします。

Lambdaの構築(2/3)
(クリックすると画像が拡大されます。)

続いてLambdaファンクションのコードを入力していきます。

今回のコードはリダイレクト用のコードです。フォワードなどのコードは後述で紹介します。
また、オレンジの箇所は任意に変更して使用するとよいです。

Lambdaの構築(3/3)
(クリックすると画像が拡大されます。)
def lambda_handler(event, context):
    
    #Definition
    redirectProtocol = "https"
    redirectDomain = "xxxx.yyyyy.com"
    request = event['Records'][0]['cf']['request']
	
    response = {
        'status': '302',
        'statusDescription': 'Found',
        'headers': {
            'location': [{
                'key': 'Location',
                'value': redirectProtocol+'://' + redirectDomain + request['uri']
            }]
        }
    }

    return response

トリガーの設定

ここまで来たら、後はトリガーとしてCloudFrontを設定すればOKです。

ただし、トリガーをCloudFrontとして設定するためには「特定のバージョンとして発行する必要がある」ことがポイントとなります。

そのため、まずはバージョンの発行から行っていきます。

作成したLambdaファンクションの「バージョン」タブから「新しいバージョンを発行」をクリックします。

新しいバージョンの発行(1/2)
(クリックすると画像が拡大されます。)

$LATESTから新しいバージョンを発行します。では、「バージョン名を任意に入力」し「発行」をクリックすればOKです。

新しいバージョンの発行(2/2)
(クリックすると画像が拡大されます。)

これで新しいバージョンが発行できたので、あとはCloudFrontをトリガーとして設定していきます。

Lambdaファンクション画面の「バージョン」タブから「発行したバージョンをクリック」し、バージョン毎の画面に移動します。

トリガーの設定(1/3)
(クリックすると画像が拡大されます。)

バージョンの画面であることを確認し、「トリガーを追加」をクリックします。

トリガーの設定(2/3)
(クリックすると画像が拡大されます。)

トリガーを追加では「CloudFront」を選択し、「先ほど作成したディストリビューションを選択」します。
lambda@Edgeへのデプロイを確認に「チェック」して「追加」をクリックします。

トリガーの設定(3/3)
(クリックすると画像が拡大されます。)

以上でLambda@Edgeの構築がすべて完了しました。

これでCloudFrontにアクセスすればリダイレクトされるようになっているはずです。

CloudFrontコンソール画面のディストリビューションで設定したディストリビューションを見るとドメイン名が確認できるので、ドメイン名にアクセスして挙動を確認してみてください。
(ただし、次項の「Lambda@Edge使用の注意点」に注意してみてください。)

リダイレクトの確認用URL
(クリックすると画像が拡大されます。)

Lambda@Edge使用の注意点

CloudFrontは世界中のエッジロケーションを使用しています。
このため、CloudFrontの設定変更などはエッジロケーションへの設定伝搬を待つ必要があります。

例えば、Lambda@Edgeを設定してから実際に動作するまでタイムラグがあります。
また、Lambda@Edgeのコードを変更しても実際に適用されるまでタイムラグがあります。

こちらのホワイトペーパーにも以下のように記述があります。

•トリガーを追加するなど、CloudFront ディストリビューションを更新した後で、トリガーで指定した関数が機能する前に、変更がエッジロケーションに伝達されるのを待つ必要があります。

Lambda@Edgeのコード紹介

ここまではリダイレクトするためのコードを紹介していましたが、
URL欄を変更せず表示だけ転送したい場合はフォワード用のコードを使用すれば実現できます。

また、パスを変えるためのサンプルコードもあるので、近い用途のモノを変更して使用してみてください。

Lambdaファンクションのコードを以下で紹介するコードに変更すれば問題ありません。ほかの構築手順はすべて上記で説明した通りです。

Lambda@Edgeでフォワードする

URL欄の内容を変えず表示する中身だけ変える(フォワードする)ためのコードです。
オレンジの箇所を任意に変更して使用します。

def lambda_handler(event, context): 
    #Definition
    redirectDomain = "xxx.yyy.com" 
    request = event['Records'][0]['cf']['request']	       
    request['headers']['host'][0]['value'] = redirectDomain
    return request
ソースコードの変更可能箇所
(クリックすると画像が拡大されます。)

Lambda@Edgeでサブディレクトリを削除してリダイレクトする

以下のようにサブディレクトリを一つ削除してリダイレクトするコードです。
オレンジの箇所を任意に変更して使用します。

動作イメージ
(クリックすると画像が拡大されます。)
def lambda_handler(event, context):
    #Definition
    redirectDomain = "xxxx.yyyyy.com"
    request = event['Records'][0]['cf']['request']
    subDirArray = request['uri'].split("/")
    del subDirArray[0:2]
    redirectSubDir = ""
    for val in subDirArray:
        redirectSubDir = redirectSubDir + "/" + val
	
    response = {
        'status': '302',
        'statusDescription': 'Found',
        'headers': {
            'location': [{
                'key': 'Location',
                'value': redirectDomain + redirectSubDir
            }]
        }
    }

    return response
ソースコードの変更可能箇所
(クリックすると画像が拡大されます。)

Lambda@Edgeでサブディレクトリを追加してフォワードする

以下のようにサブディレクトリを一つ追加してフォワードするコードです。
オレンジの箇所を任意に変更して使用します。

動作イメージ
(クリックすると画像が拡大されます。)
def lambda_handler(event, context): 
    #Definition
    redirectDomain = "xxx.yyy.com" 
    subDir =  "zzzz"
    request = event['Records'][0]['cf']['request']	       
    request['headers']['host'][0]['value'] = redirectDomain
    request['uri'] =  "/" + subDir + request['uri']
    return request
ソースコードの変更可能箇所
(クリックすると画像が拡大されます。)

以上です。本記事が参考になったという方、似たようなAWSの使い方ハンズオンを以下のサイトにまとめています。他のAWSサービスの使い方の参考に覗いてみてください。

Check Out! Recommended You
ハンズオンで学べるAWS

AWSをもっと知りたいという方に向けて「ハンズオンで学べるAWS」を提供しています。

興味のあるAWSサービスをハンズオンでぜひ試して触ってみてください。

Spread the love