はじめに
この記事は”AWS Hands-on for BeginnersAmazon CloudFrontおよびAWS WAFを用いて エッジサービスの活用方法を学ぼう”を
参考に記事にしました。
今回構築するアーキテクチャ
今回構築するアーキテクチャは以下のようになっている。
AWSグローバルインフラストラクチャとエッジサービスについて
AWS クラウドは、全世界 26 の地域にある 84 のアベイラビリティーゾーンにまたがっており、オーストラリア、カナダ、インド、イスラエル、ニュージーランド、スペイン、スイス、およびアラブ首長国連邦 (UAE) に 24 アベイラビリティーゾーンと 8 AWS リージョンを追加する計画が発表されている。(2022年8月現在)
AWSのサービスは大きく2つに分けられ、「エッジサービス」と「リージョンサービス」がある。
エッジサービスはエッジロケーションで提供されるサービスであり、「Amazon Route 53」、「AWS Global Accelerator」、「Amazon CloudFront」、「AWS WAF」、「AWS Shield」がある。
一方、リージョンサービスはリージョンエリアで提供されるサービスであり、「Amazon EC2」、「Amazon VPC」、「Amazon RDS」、「Amazon S3」などがある。
エッジサービスを導入することで解決できる課題として以下がある。
- サーバーから遠い場所にいるユーザーの高レイテンシーでのサービス提供
- 突発的な大量のリクエストに対する対応
- DDos攻撃やウェブアプリケーションに対する攻撃
などがある。
AWSのエッジサービスとコンテンツデリバリーネットワークについて
コンテンツデリバリーネットワークであるCloudFrontを用いた流れ図を以下に示している。
図から分かる通り、2回目以降はCloudFrontがコンテンツをキャッシュしており、オリジンサーバーにリクエストを送らず、ユーザーにレスポンスを返すことができており、レスポンス速度を向上させることができる。
とはいえ、全てのコンテンツをキャッシュしていいわけではないので、「静的コンテンツ」のみをキャッシュしていいように設定する必要がある。
「静的コンテンツ」・・・ユーザーのリクエストによって変わらないコンテンツのこと
「動的コンテンツ」・・・ユーザーのリクエストによって変わるコンテンツのこと
Amazon CloudFrontハンズオン1
S3の設定を行う
CloudFrontの設定の前にS3に静的コンテンツを格納する。
マネジメントコンソールでリージョンをバージニア北部に設定→S3を検索→バケットを作成を選択。
以下のように設定し、バケットを作成した。
バケット名:hfb-taiboy
リージョン:バージニア北部
次にS3に静的コンテンツをアップロードする。
ディレクトリ配置は以下のようになっている。
root/
┣index.html
┣static/
┣image/cloudfront.png
┣js/script.js
┣css/styles.css
<!DOCTYPE html>
<html>
<head>
<link rel="icon" type="image/x-icon" href="static/image/cloudfront.png">
<link href="static/css/styles.css" rel="stylesheet" type="text/css">
<script src="static/js/script.js"></script>
</head>
<body>
<form id="form1" action="#">
<ul>
<li>
<img src="static/image/cloudfront.png" width="100" height="100">
</li>
<li>
<p>Input Message</p>
<textarea id="input_message" rows="4" cols="40"></textarea>
</li>
<li>
<input type="button" onclick="func1()" value="Send" />
<input type="button" onclick="func2()" value="All Clear" />
</li>
<li>
<br />
<p>Output Message</p>
<textarea id="output_message" rows="4" cols="40"></textarea>
</li>
</ul>
</form>
</body>
</html>
function func1() {
var apiurl = 'https://' + document.domain + '/api?input_text=' + document.getElementById("input_message").value;
var request = new XMLHttpRequest();
request.open('GET', apiurl, true);
request.responseType = 'text';
request.onload = function () {
var data = this.response;
document.getElementById("output_message").innerHTML = data;
};
request.send();
}
function func2() {
document.getElementById("input_message").value = '';
document.getElementById("output_message").innerHTML = '';
}
CloudFrontの設定
CloudFrontの設定の大枠はディストリビューションといい、そのなかに「ビヘイビア」と「オリジン」がある。
このハンズオンでは、ビヘイビアはパスの設定、オリジンはバックエンドとなるオリジンを指定するものと考える。
マネジメントコンソールからCloudFrontを選択し、ディストリビューションを作成をクリックする。
オリジン設定
オリジンドメインネーム:hfb-taiboy
S3バケットアクセス:はい
オリジンアクセスアイデンティティ:新しいOAIを作成
バケットポリシー:はい
※S3バケットアクセス:クラウドフロントからS3バケットにアクセスするためのポリシーを有効にする。
ビヘイビア設定
以下のように設定した。
ビューワープロトコルポリシー:redirect HTTP to HTTPS(HTTPSの通信のみに限りたいため)
キャッシュポリシー:Caching Disbabled(キャッシュさせない設定にしてみる。)
ディストリビューション設定
デフォルトルートオブジェクト:index.html(こうすることで URLの最後にindex.htmlがなくてもアクセスできるようになる。)
ディストリビューション設定で「カスタムドメイン」や「SSL証明書」を設定することができる。(ピンクの枠)
ドメインへアクセス
CloudFrontに表示されているドメインにアクセスする。
開発者ツールのNetworkタブを開く→画像を選択し、x-cacheの項目を見る
Miss from CloudFrontと書いており、CloudFrontでキャッシュがヒットしていないことが分かる。
なので、オリジンサーバーがCloudFrontを経由してレスポンスを返したということになる。
※x-cacheとはユーザーのリクエストがキャッシュにヒットしたかどうかを表す。
Amazon CloudFront設定2
CloudFrontにキャッシュを持たせる。
Cacheポリシーの設定項目
TTL settings:キャッシュ時間のコントロールが可能
- デフォルトTTL:オリジンがキャッシュコントロールヘッダーを指定しない場合に利用
- 最小TTL:CloudFront側でキャッシュすべき最小TTL
- 最大TTL:CloudFront側でキャッシュすべき最大TTL
Cache Key Contents:キャッシュのKeyが設定可能
- Headers:キャッシュのKeyとなるHTTPヘッダーを指定
- Cookies:キャッシュのKeyとなるクッキーを指定
- Query strings:キャッシュのKeyとなるクエリストリングを指定
CloudFrontのコンソール画面から→ポリシー→新しいポリシーを作成
名前:hfb-cachepolicy
これだけ入力し、ポリシーを作成をクリック
ポリシーができたらCloudFrontに設定する。
ディストリビューション→先ほどのディストリビューションを選択→ビヘイビアタブ→新しいビヘイビアを作成
パスパターン:static/*
ビューワープロトコルポリシー:Redirect HTTP to HTTPS
キャッシュポリシー:hfb-cachepolicy(先ほど作成したポリシー)
作成ボタンをクリック
以下のように設定できた。
static/*のリクエストはキャッシュポリシーhfb-cachepolicyを実行し、それ以外はcacheDisableポリシーを実行する。
webアプリを更新して、開発者ツールの画像を選択してみると、x-cacheの部分に「Hit from cloudfront」とあるので、うまくキャッシュされていることが分かる。
Amazon CloudFront 設定3(動的コンテンツの配信)
Amazon API Gateway とAWS Lambdaを用いた動的コンテンツとなる、APIの実装を行う。
Lambda関数を作成
マネジメントコンソールからLambdaを開く→新しい関数を作成(右上のリージョンが「バージニア北部になっているか確認する。」)
関数名: h4b-function
ランタイム: Python3.8
と設定し、関数を作成する。
以下のコードを貼り付ける。
import boto3
def lambda_handler(event, context):
translate = boto3.client(service_name='translate', use_ssl=True)
result = translate.translate_text(Text=event['queryStringParameters']['input_text'], SourceLanguageCode="ja", TargetLanguageCode="en").get('TranslatedText')
return {
'statusCode': 200,
'body': result
}
次にこのラムダ関数に紐づいているロールにtranslateReadonlyポリシーをアタッチする。
設定→アクセス権限→ポリシーをアタッチ→検索窓にtranslateと検索し、translateReadonlyポリシーをアタッチする。
APIGatewayを構築する
マネジメントコンソールから「APIGateway」と入力する。→リージョンが「バージニア北部」なのを確認する。→APIを作成するをクリック。→RESTAPIをクリック
プロトコル:新しいAPI
名前:h4b-api
エンドタイプ:リージョン
と設定した。
次に、
アクションをクリックし、メソッドを作成→プルダウンからGETを選び、横のチェックをクリック。
統合タイプ:Lambda関数
Lambdaプロキシ統合を使用にチェック
Lambdaリージョン:us-east-1(バージニア北部なので)
Lambda関数:h4b-function
に設定。
次にこのAPIに渡すクエリストリングを設定するため、メソッドリクエストを編集する。
URLクエリ文字列パラメータのタブからクエリ文字列の追加をクリックする。→「input_text」を入力し、チェックする。
次に、アクションからAPIのデプロイを選択
デプロイされるステージ:[新しいステージ]
ステージ名:api
と設定した。
URLの呼び出しのURLをクリックし、「?input_text=こんにちは世界」をURLの最後に付け加えることでHello Worldと返る。
ここまでくると、APIGatewayはうまく設定できた。
動的コンテンツをCloudFrontへ紐づける
AmazonAPIGatewayをCloudFrontに紐づける。
AmazonAPIGatewayでは「input_text」というクエリ文字列パラメータを設定したことから、CloudFront側でもそのクエリ文字列を設定しないといけない。
ユーザーからのリクエストは一旦、CloudFrontが受け取るため、「ヘッダー」「クッキー」「クエリストリングス」の情報はCloudFrontにて、フィルタリングされた状態でオリジンサーバーに送られる。なので、デフォルト設定のままだと、ユーザーが付与したクエリストリングスはオリジンサーバーには渡らないことになる。
ユーザーが付与したクエリストリングスをオリジンに送りたい場合はCloudFrontのフィルタリングにてホワイトリストを追加する必要があり、この設定を「オリジンリクエストポリシー」という。このオリジンリクエストポリシーはビヘイビアの設定項目の一部として行う。
オリジンリクエストポリシーの作成
マネジメントコンソールからCloudFrontと検索する。→ポリシーを選択しオリジンリクエストポリシーのタブを選択する。→オリジンリクエストポリシーを作成をクリック。
以下のように設定した。
オリジンの設定
ここまで来たら、ディストリビューションズに移り、自分が設定したCloudFrontに設定をアタッチする。
今回はAPIGatewayを新しいオリジンとして追加していきたいので、オリジンのタブを選択し、オリジンの作成をクリックする。
オリジンドメインネーム:https://「ご自身のドメイン」.us-east-1.amazonaws.com/
オリジンプロトコルポリシー:HTTPS only
ビヘイビアの設定
このオリジンにアクセスするためのビヘイビアを設定する。
パスパターンはAPIGatewayのステージ名「api」とし、オリジンとオリジングループはAPIGWのドメインをコピペした。
ビューワープロトコルをHTTPSのみの「Redirect HTTP to HTTPS」とした。今回は動的コンテンツのため、キャッシュポリシーを「CashingDisabled」にし、
オリジンリクエストポリシーを先ほど作成した「h4b-originrequestpolicy」を選択した。
CloudFrontのマネジメントコンソールからビヘイビアタブを選択し、ビヘイビアを作成をクリック
以下のように設定した。
キャッシュコンテンツの確認
クラウドフロントのドメインネームを検索窓に貼り付け、アプリケーションを確認する。
下の画像から動的コンテンツのx-cacheがMiss from cloudfrontになっていることがわかる。
AWS WAFをAmazon CloudForntに紐づける
マネジメントコンソールからAWS WAFを検索(このときリージョンがグローバルになっていることを確認。)し、create WEB ACLをクリック。
name:h4b-waf
Resourse type:CloudFront distoributions
以上を設定したら、下へスクロールし、Associated AWS resourcesの項目でAdd AWS resourcesをクリック。
先ほど作成したCloudFrontを選択し、Addをクリックする。
ここまでできたら、Nextボタンをクリック。
次にルールを設定する画面になるので、Add rules をクリックし、自分独自のルールを設定するので、「Add my own rules and rule group」を選択する。
name:h4b-rule
if a request: matches trhe statement
Inspect: Originates from a country in
country codes: Japan
Action:Block
Ip address to use to determine the country originの項目では、Source IP addressを選択しているが、IP address in headerにすると、ソースIPアドレス以外からIPアドレスを引っ張ることができ、例えばXFF(X-Forwarded-For)の中のIPアドレスを引っ張ることもできる。
X-Forwarded-Forとは、HTTPヘッダフィールドの1つであり、ロードバランサなどの機器を経由してWebサーバに接続するクライアントの送信元IPアドレスを特定する際のデファクトスタンダード。
日本からのアクセスをブロックしてみる。
ここまで入力したらAdd ruleをクリック。その次のプライオリティーやメトリクスはデフォルトのまま設定した。
サマリーの画面で、問題ないことを確認し、Create WEB ACLをクリック。
CloudFrontに上部の設定が反映されているか確認する。ドメインにアクセスしてみると、以下のようなページが表示されるため、
設定が正しくできていることがわかる。
次にマネージドルールを追加する。再度、AWS WAFと検索し、Wab ACLsのタブをクリックする。このとき、リージョンがグローバルになっていることを確認する。
先ほど作ったWebACLsを選択し、Rulesタブをクリック。右上のAddRuleからAdd managed rule groupsを選択する。AWS managed ruleからCore rule setを選択する。この設定のまま、Add rulesをクリックする。プリオリティーもそのままでSaveをクリック。これでマネージドルールが設定できた。
リソースの削除手順
Amazon CloudFrontの削除
↓
AWS WAFの削除
↓
Amazon API Gatewayの削除
↓
AWS Lambdaの削除
↓
Amazon S3の削除
Amazon CloudFrontの削除
該当のディストリビューションを選択し、無効にする。直接、削除はできない。
しばらくして、ステータスが無効、状態がデプロイになったら、ページを更新し、削除を選択する。
次にキャッシュポリシー、オリジンリクエストポリシーも削除する。
ポリシータブを押して自身が作成したポリシーを削除。オリジンリクエストポリシーのタブに移動し、これも自身が作成した ポリシーを削除する。
Amazon S3の削除
該当のバケットを選択し、まず、「空にする」を選択後、削除する。