CloudFront FunctionsとLambda@Edgeの比較と実践
それぞれの概要と違い
CloudFront FunctionsとLambda@Edgeの概要について、以下に要点を表形式でまとめました。
※その他の違いや詳細については、AWSドキュメント「CloudFront Functions と Lambda@Edge の違い」をご参照ください。
項目 | CloudFront Functions | Lambda@Edge |
---|---|---|
概要 | 簡単な処理、低レイテンシ要求の処理 | 複雑な処理、大規模なトラフィック、長時間実行の処理 |
プログラミング言語 | JavaScript (ECMAScript 5.1 準拠) | Node.js と Python |
関数の持続時間 | サブミリ秒 | 最大 5 秒 (Viewer request、Viewer response) 最大 30 秒 (Origin request、Origin response) |
スケール量 | 毎秒 1000 万 件 | 1 リージョンあたり毎秒 1万 件まで |
対応するCloudFront イベント | Viewer request Viewer response | Viewer request Viewer response Origin request Origin response |
Viewer Request/ResponseとOrigin Request/Responseについて
- Viewer Request
- クライアント(ユーザー)が CloudFront にリクエストを送信した直後に実行される
- Viewer Response
- CloudFront がクライアントにレスポンスを返す直前に実行される
- Origin Request
- CloudFront がオリジンサーバー(例: S3やEC2)にリクエストを送信する直前に実行される
- Origin Response
- オリジンサーバーから CloudFront にレスポンスが戻ってきた直後に実行される
Viewer Request/Response と Origin Request/Response のトリガーを使い分けることで、CloudFront 関数や Lambda@Edge を適切に活用し、キャッシュの前後でコンテンツを効率的に操作できます。
CloudFront Functions で利用できない機能が必要な場合でも、Lambda@Edge を使ってキャッシュの前後でコンテンツを操作できます。
参考)Introducing CloudFront Functions – Run Your Code at the Edge with Low Latency at Any Scale
料金比較
項目 | CloudFront Functions | Lambda@Edge |
---|---|---|
リクエスト料金 | 100 万回あたり 0.1 USD | 100万件あたり USD 0.60 |
コンピューティング料金 | なし | あり(128 MB-秒の使用につき 0.00000625125 USD) |
無料枠 | あり(1 か月あたり 200 万件の CloudFront 関数呼び出し) | なし |
※AWSドキュメント「Amazon CloudFront の料金」
※AWSドキュメント「AWS Lambda 料金」
料金の例
1か月に100万回リクエストされ、1か月のコンピューティング時間が合計100万 秒(毎回の実行時間が 100 ミリ秒)であった場合、発生する料金は以下のように計算されます。
項目 | CloudFront Functions | Lambda@Edge |
---|---|---|
1 か月のコンピューティング料金 | なし | 1000,000 × 0.00000625125 USD = 6.3 USD |
1 か月のリクエスト料金 | 100 万回あたり 0.1 USD | 100万件あたり USD 0.60 |
無料枠 | あり(1 か月あたり 200 万件) | なし |
合計 | 0 USD(※無料枠が適用された場合) | 6.9 USD |
CloudFront FunctionでBasic認証+IP制限の実装
私がCloudFront Functionを触ったことがなく、CloudFront Functionでどの程度の処理なら出来るかのイメージが分からないので、とりあえずCloudFront Functionを使ってBasic認証+IP制限の実装をやってみようと思います!
- 全体の流れ
- ステップ1: S3 作成
- ステップ2: CloudFront 作成
- ステップ3: S3 バケットポリシー編集
- ステップ4: (練習)リダイレクト用のCloudFront Functions作成)
- ステップ5: CloudFront FunctionでBasic認証+IP制限を実装
ステップ1: S3作成
- 今回オリジンをS3にするため、S3を作成します。
作成後、以下のフォルダ構成でフォルダ・HTMLファイルを作成し、S3バケットへのアップロードをします。
フォルダ構成はこちらになります。
/
└── index.html
└── management/
└── index.html
<!DOCTYPE html>
<html lang="ja">
<h1>Welcome</h1>
</html>
<!DOCTYPE html>
<html lang="ja">
<h1>Welcome manager</h1>
</html>
ステップ2: CloudFront 作成
- 続いて、CloudFrontを作成します。
- 作成する際にいくつかの項目を設定します。
- Origin domain:ステップ1で作成したS3を選択
- オリジンへのアクセス制御方法:OACを使用
- Create new OACをクリックして、任意の名前で作成可能
- 今回は検証のため、ウェブアプリケーションファイアウォール (WAF)は有効にせず作成
- CloudFront 作成後にAWSマネジメントコンソール上部に以下の通知が来るので、「ポリシーをコピー」をクリックお願いします。ステップ3の「S3バケットポリシー編集」で使用します。
ステップ3: S3バケットポリシー編集
- ステップ2の最後にコピーしたポリシーをステップ1で作成したS3のバケットポリシーに設定します。
例:
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::{S3リソース名}/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "{CloudFrontのArn}"
}
}
}
]
}
一度アクセスできるか確認
CloudFrontのコンソールにて、ステップ2で作成したCloudFrontのディストリビューションドメイン名をコピーしてアクセスしてみます。
そのドメインに/index.html
を足してアクセスし、「Welcome」と表示されればOKです!
例:https://xxxxxxxxxxx.cloudfront.net/index.html
練習:リダイレクト用のCloudFront Functions作成
ここで一度練習を入れました!必要ない方は飛ばしていただいても大丈夫です!
https://xxxxxxxxxxx.cloudfront.net
にアクセスした際に、https://xxxxxxxxxxx.cloudfront.net/index.html
にリダイレクトされるように設定します。
- CloudFrontのコンソールにて、ビヘイビアを作成します。
- パスパターンを
/
- オリジンに作成したS3を設定
- パスパターンを
- 作成後の設定画面がこちらになります。
- 続きまして、CloudFrontのコンソールのサイドメニューから関数をクリックし、CloudFront Functionsを作成します。
- 続いて実行するコードを記載し保存します。
function handler(event) {
var request = event.request;
var uri = request.uri;
// リクエストパスが `/` の場合に `index.html` を追加
if (uri === "/") {
request.uri += "index.html";
}
return request;
}
- 続いて実行するコードをテストをするために、テスト画面にて項目のURLパスを
/
にして関数をテストします。
- このように成功すればOKです!
実行結果に記載されているコンピューティング使用率が50以上であれば、関数コードの最適化するか、Lambda@Edgeへの移行が必要になります。
:::note info
- コンピューティング使用率の値:
- 1 ~ 50 — この機能は最大許容時間を快適に下回っており、スロットリングなしで実行されます。
- 51 ~ 70 — 関数は最大許容時間に近づいています。関数コードを最適化することを検討してください。
- 71 ~ 100 — 関数が最大許容時間に非常に近いか、それを超えています。ディストリビューションに関連付けた場合、CloudFront は、この関数をスロットリングする可能性があります。
参考)AWSコンソール画面の説明文より抜粋
:::
- テストを実行した後、「関数を発行」をクリックすると、ディストリビューションに関連付けの設定画面が表示されるので、作成したディストリビューションのキャッシュビヘイビア
/
を関連付けることができます。
- クライアント(ユーザー)が CloudFront にリクエストを送信した直後に実行されるようにしたいので、イベントタイプでViewer Requestを選択しています。
- 関連付けが完了したのち、
https://xxxxxxxxxxx.cloudfront.net
にアクセスし、/index.html
の内容が表示されていればOKです!
ステップ4: CloudFront FunctionでBasic認証+IP制限を実装
それでは、先ほど実施していただいた手順と同じように、CloudFront FunctionでBasic認証+IP制限を実装していきます。https://xxxxxxxxxxx.cloudfront.net/management/index.html
へアクセスする際に、指定したIPアドレスからのアクセスのみを許可し、さらにBasic認証を要求する実装になります。
- CloudFrontのコンソールにて、ビヘイビアを作成します。
- パスパターンを
/management/*
- オリジンに作成したS3を設定
- パスパターンを
- 作成後の設定画面がこちらになります。
- 再度新規のCloudFunctionsを作成し、以下のコードを記載し保存します。
- 以下の三つの部分を変更してコードを使用してください。
- XX.XX.XX.XX :あなたの利用しているIPアドレス
- yourUsername :任意のユーザー名
- yourPassword :任意のパスワード
function handler(event) {
var request = event.request;
var headers = request.headers;
var clientIP = event.viewer.ip;
console.log('Client IP:'+clientIP);
// アクセス許可するIPリスト
var IP_WHITE_LIST = {
'XX.XX.XX.XX': true, // 要変更
};
// Basic認証のユーザー名とパスワード
var credentials = {
username: "yourUsername", // 要変更
password: "yourPassword", // 要変更
};
// Basic認証のためにユーザー名とパスワードを Base64 でエンコード
var encodedAuth = Buffer.from(credentials.username + ':' + credentials.password).toString('base64');
var expectedAuthHeader = 'Basic ' + encodedAuth;
// クライアントIPが許可されているかを確認
var isPermittedIp = IP_WHITE_LIST[clientIP] || false;
console.log(isPermittedIp);
if (isPermittedIp) {
// Authorizationヘッダーの有無と認証情報をチェック
if (headers.authorization && headers.authorization.value === expectedAuthHeader) {
console.log("Authorization successful for IP:"+clientIP);
return request; // 認証成功
} else {
console.log("Authorization failed for IP:"+clientIP);
// 認証失敗時に401レスポンスを返す
return {
statusCode: 401,
statusDescription: 'Unauthorized',
headers: {
'www-authenticate': { value: 'Basic realm="Enter credentials"' },
},
};
}
} else {
// 許可されていないIPの場合403レスポンスを返す
console.log("Forbidden access for IP:"+clientIP);
return {
statusCode: 403,
statusDescription: 'Forbidden',
};
}
}
- 想定外のIPアドレスからのアクセスが禁止されていることを確認するために、テスト画面にて以下の設定を行い、実行します。
- URLパス:
/management/index.html
- IPアドレス:1.2.3.4
- URLパス:
- テストを実行した結果、ステータスが
403 Forbidden
となっていればOKです。この結果により、IPアドレス1.2.3.4
からのアクセスが適切に禁止されていることが確認できます。
- 次に、CloudFront Functionsに登録されているIPアドレスからのアクセスが許可されているかを確認するため、テスト画面にて以下の設定を行い、実行します。
- URLパス:
/management/index.html
- IPアドレス:あなたの利用しているIPアドレス
- URLパス:
- テストを実行した結果、ステータスが
401 Unauthorized
となっていればOKです!401 Unauthorized
エラーは、IPアドレスからのアクセスが許可された後に、Basic認証においてエラーとなっているだけです。つまり、このテスト結果から、ご利用のIPアドレスからのアクセスが許可されていることが確認できます。
- テストを実行した後、「関数を発行」をクリックすると、ディストリビューションに関連付けの設定画面が表示されるので、作成したディストリビューションのキャッシュビヘイビア
/manager/*
を関連付けることができます。
- 関連付けたあと、アクセスするとBasic認証を求められます。
- ユーザー名とパスワードを入力し、「Welcome manager」と表示されればOKです!
まとめ
CloudFront FunctionsとLambda@Edgeの比較と実践を行いました!
これまでLambda@Edgeを利用して実装していたものをCloudFront Functionsに移行することも検討してみると良いかもしれません。
CloudFront Functionsの導入を検討されている方々にとって、少しでも参考になれば幸いです!