はじめに
以前、AWS WAF によるアクセス制限(IP制限)に関して投稿した際、比較対象として2021年にリリースされたCloudFront Functions(以降 CF Functions)を取り上げました。
・昨年リリースされた新機能。Lambdaに比べ簡易なjavascriptしか書けませんが、その分低コスト、高速処理が売り。そして、スクリプトを利用することで柔軟な対応が可能。
本件ですとRequest Headerより送信元IPを判別し、任意の宛先へリダイレクトさせることも出来るかと思います。
(apacheのように時間設定も出来そうです。こちら近い内に試してみたく思います)
現在CF経由のアクセス制御にはWAFでもLambda@Edgeでもなく、全面的にCF Functionsを利用しています。そこで今回、どのように利用しているかをご紹介致します。
メリット
🔵 コストパフォーマンスがよい
◎ 引用
・前回の記事より
5-1. 本WAFの月額利用料
5-2. CloudFront Functionsの料金と比較
◎ CF Functionの利用料金
公式DocよりCF Functionsの料金 の [エッジコンピューティング][無料利用枠]より
■ 無料利用枠
2,000,000 件の CloudFront Function 呼び出し
■ 利用料金
100 万件の呼び出しあたり 0.10 USD
◎ AWS WAFとの比較
条件 : アクセス制御対象が 200万Req/mon だった場合
比較結果 : CF Functionsならば無料枠だけで対処可能。WAFだとシンプルな設定内容(※)でも 9.20USD/mon 掛かる
(※) IPアクセス制限を適用した場合。詳細は上述した前回の投稿を参照ください
◎ Lambda@Edgeとの比較
条件 : (同上)
比較結果 : CF Functionsの場合、無料で利用可。Lambda@Edgeの場合、1.2 USD + メモリ使用量別の実行時間課金
▽ 補足
Lambda@Edgeの料金
リクエスト料金は、リクエスト 100万件あたり 0.60USD
時間は、1 GB-秒の使用につき 0.00005001USD
現在、Lambda@Edge に無料利用枠はありません。
🔵 機能が充実かつ使いやすい
・CloudFrontへのアクセス(HTTP Request)制御であれば充分な機能が備わっています
-
Serverless
-> Lambda@Edge そして AWS WAFも同様ですね -
簡易言語であるJavaScript対応 (正確にはECMAScript 5.1準拠)
-
処理が早い
CloudFront Functions を使用したエッジでのカスタマイズよりCloudFront Functions の runtime 環境は、起動時間が 1 ミリ秒未満、毎秒数百万のリクエストを処理するようにすぐにスケールでき、高い安全性を誇ります
-
開発が容易
・build/deploy不要。コンソールよりソースコード直接記入でもOK
※ AWS CLIによる CF Functions作成からソースコード・アップロードも可(参照) -
CI/CDに関して、IaCとの統合管理も可能
・ちなみにTerraformの一部として私は管理しています -
簡易テスト機能
・直感的かつシンプルにテストが実施可能 -
CWログ出力あり
・標準で N.Virginia の CW logsに[/aws/cloudfront/function/(Function名)] としてログが出力される
デメリット
🟣 機能面
-
簡易スクリプトのみ対応のため、利用できる関数や定義に制限がある
-
対象はCFへの Viewer Request/Viewer Responseに限られる(Origin Req/Resは対象外)
実装例
では実際にCFへのリクエスト(viewer request)に対し行っている制御を挙げます
機能一覧
- Basic Authentication(ベーシック認証)
- Path Completion(パス補完)
- Maintenance Mode with time control(メンテナンスモード切り替え、時間指定付き)
- IP restriction(アクセス元IPアドレスによる制御)
- referer restriction(アクセス元refererによる制御)
- URI(path) check(アクセス先による制御)
概要図
全体構成図
CF Functionsによるアクセス制御部
・上記全体構成よりCF Functionsの箇所をピックアウト
コーディング
要点
・HTTP Request/Responseは、json形式のeventととしてCF Functionsで受け取ります。
そして、受け取ったオブジェクトを活用して制御していくことになります。
公式よりイベントオブジェクトの例
{
"version": "1.0",
"context": {
"distributionDomainName": "d111111abcdef8.cloudfront.net",
"distributionId": "EDFDVBD6EXAMPLE",
"eventType": "viewer-response",
"requestId": "EXAMPLEntjQpEXAMPLE_SG5Z-EXAMPLEPmPfEXAMPLEu3EqEXAMPLE=="
},
"viewer": {
"ip": "198.51.100.11"
},
"request": {
"method": "GET",
"uri": "/media/index.mpd",
"querystring": {
"ID": {
"value": "42"
},
"TTL": {
"value": "1440"
},
(省略)
},
"headers": {
"host": {
"value": "video.example.com"
},
"user-agent": {
"value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0"
},
"accept": {
"value": "application/json",
"multiValue": [
{
"value": "application/json"
},
(省略)
]
},
"accept-language": {
"value": "en-GB,en;q=0.5"
},
"accept-encoding": {
"value": "gzip, deflate, br"
},
"origin": {
"value": "https://website.example.com"
},
"referer": {
"value": "https://website.example.com/videos/12345678?action=play"
},
"cloudfront-viewer-country": {
"value": "GB"
}
},
"cookies": {
"Cookie1": {
"value": "value1"
},
(省略)
}
},
サンプルコード
サンプルコード(私のGitHubより)
補足説明
-
Basic Authentication(ベーシック認証)
・特定のRequestに対して、Basic認証をかけています -
Path Completion(パス補完)
・ファイル指定のないRequest(/で終わる)の場合、index.htmlを参照させるようにしています -
Maintenance Mode with time control(メンテナンスモード切り替え、時間指定付き)
・指定時間にメンテナンスモード(=メンテナンスページへリダイレクト)へ切り替え、指定時間に解除されるよう実装しています -
IP restriction(アクセス元IPアドレスによる制御)
・よりセキュアなアクセス領域の制限として、アクセス元のIPアドレスを評価しています -
referer restriction(アクセス元refererによる制御)
・図にありますとおり、メインサイトからのみアクセスを許可したいOriginがある場合に適用しています -
URI(path) check(アクセス先による制御)
・特定のURI(パス)への制御になります
リダイレクトにquerystringを含める場合
- サンプルスクリプトには含めていませんが、パスおよびqueryをリダイレクト先に引き継ぎたい場合、URIおよびquerystringもリダイレクト先に含める必要があることご注意ください。
例) https://abc.example.com/index.html?region=ap-southeast-1 ↓ (redirect) https://def.example.com/index.html?region=ap-southeast-1
- またquerystringが複数ある場合、それを判定し処理する必要があることも合わせてご注意ください。
参考
[aws-samples/amazon-cloudfront-functions]の issuesより