Lambda@EdgeはLambdaをCloudFrontのエッジロケーションで実行するもので、CloudFrontで受けたアクセスに対して何かしらの処理を実行するのに安くて便利な方法です。
今回はLambda@Edgeを使ってリダイレクトやフォワードするための方法を紹介します。
リダイレクトやフォワードの為にわざわざApacheサーバーなどを用意しなくてよいですし、Lambdaを使うことで(常時サーバー立ち上げが必要ないので)非常に安く済みます。
手段の一つとして覚えておき活用してもらえたら嬉しく思います。
本記事ではLambda@Edgeの基本的な構築の流れを1から解説しています。
既に知っている場合は飛ばしながら読んでください。
アーキテクチャ構築の流れ
さっそく構築手順を紹介していきます。
構築の流れは以下のようになります。
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用のIAMロールを作成し、信頼関係を追加する必要がある
- Lambda@EdgeのLambdaファンクションはバージニア北部リージョンに作成する
- Lambdaファンクションから特定のバージョンを発行してトリガー設定が必要になる
- LambdaのトリガーをCloudFrontにすることでLambda@Edgeとなる
CloudFrontを作成
ダミーオリジンの作成
まずはCloudFrontを構築するためのダミーオリジン用のS3バケットを作成していきます。
CloudFrontは必ずオリジンを設定しなければならないため、オリジン用として空のS3バケットを用意しておけばOKです。
S3コンソール画面の「バケット」から「バケットを作成」をクリックします。
「バケット名」だけ入力し「バケットを作成」をクリックします。
バケットの各種設定はデフォルトから変更する必要はありません。
CloudFrontの構築
ダミーバケットが作成出来たらCloudFrontの構築を行います。
CloudFrontコンソール画面の「ディストリビューション」から「ディストリビューションを作成」をクリックします。
「オリジンドメイン」だけ先ほど作成したダミーバケットを指定し「ディストリビューションを作成」をクリックします。
CloudFrontの各種設定はデフォルトから変更する必要はありません。
ここまででLambda@Edgeを実行するCloudFrontが構築できました。
Lambda@Edgeを構築
実行用のCloudFrontができたので、続けてLambda@Edgeを構築していきます。
Lambda@Edge用のIAM作成
Lambda@Edgeでは通常のLambda用IAMロールから「信頼関係」などを変更したIAMロールを使用する必要があります。
まずはLambda@Edge用のIAMロールを作成していきます。
IAMコンソール画面の「ロール」から「ロールを作成」をクリックします。
信頼されたエンティティを選択では、「AWSのサービス」から「Lambda」を選択し、「次へ」をクリックします。
許可を追加では、検索窓に「lambda」と入力し、「AWSLambdaRole」を選択して「次へ」をクリックします。
名前、確認、および作成では、「Role名」を入力して「ロールを作成」をクリックします。
このままではデフォルトのLambda用IAMロールと変わらないので、Lambda@Edge用に信頼関係を追加していきます。
IAMコンソール画面の「ロール」から先ほど作成したIAMロールを選択し、「信頼関係」タブの「信頼ポリシーを編集」をクリックします。
信頼関係に「edgelambda.amazonaws.com」を追加してください。
追加する位置は以下のオレンジ箇所になります。
ここまでで、Lambda@Edgeを実行できるIAMロールはできました。
ここからはCloudWatch Logsにログを出力できるようにさらにIAMポリシーを追加していきます。
IAMコンソール画面の「ポリシー」から「ポリシーを作成」をクリックします。
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ポリシーを作成出来たら、IAMコンソール画面の「ロール」から作成したLambda@Edge用ロールを選択して「許可」の「アクセス許可を追加」から先ほど作成した「ポリシーをアタッチ」します。
ここまでで、Lambda@Edgeを実行するためのIAMロール作成が完了しました。
Lambdaの構築
ここまで来たらいよいよLambdaを構築していきます。
Lambda@Edgeを作成するうえでのポイントはLambdaを「バージニア北部リージョンに構築すること」です。
CloudFrontはグローバルリージョンに作成されるのでCloudFrontをトリガーにできる設定できるのはバージニア北部リージョンのLambdaのみです。
Lambdaコンソール画面の「関数」から「バージニア北部リージョン」を選択したうえで「関数の作成」をクリックします。
「関数名」を任意で入力し、ランタイムを「Python3.8」にします。
デフォルトの実行ロールの変更から「既存のロールを使用する」を選択し、「作成したIAMロール」を入力して「関数の作成」をクリックします。
続いてLambdaファンクションのコードを入力していきます。
今回のコードはリダイレクト用のコードです。フォワードなどのコードは後述で紹介します。
また、オレンジの箇所は任意に変更して使用するとよいです。
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ファンクションの「バージョン」タブから「新しいバージョンを発行」をクリックします。
$LATESTから新しいバージョンを発行します。では、「バージョン名を任意に入力」し「発行」をクリックすればOKです。
これで新しいバージョンが発行できたので、あとはCloudFrontをトリガーとして設定していきます。
Lambdaファンクション画面の「バージョン」タブから「発行したバージョンをクリック」し、バージョン毎の画面に移動します。
バージョンの画面であることを確認し、「トリガーを追加」をクリックします。
トリガーを追加では「CloudFront」を選択し、「先ほど作成したディストリビューションを選択」します。
lambda@Edgeへのデプロイを確認に「チェック」して「追加」をクリックします。
以上でLambda@Edgeの構築がすべて完了しました。
これでCloudFrontにアクセスすればリダイレクトされるようになっているはずです。
CloudFrontコンソール画面のディストリビューションで設定したディストリビューションを見るとドメイン名が確認できるので、ドメイン名にアクセスして挙動を確認してみてください。
(ただし、次項の「Lambda@Edge使用の注意点」に注意してみてください。)
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サービスの使い方の参考に覗いてみてください。