【AWS】アクセス制限のある動的サイトを作成する方法
はじめに
こんにちは!はじめまして!
ユニフォームネクスト株式会社 のシステムエンジニアKです。
諸々割愛しますが、社内行事でゲームセンターを作ることになったので
オリジナルPCゲームを作って社内限定で公開することにしました。
備忘録を兼ねて何をしたかを記載します。
もしゲームセンターを作ることがあればぜひ参考にしてください🙌
前提
この記事にあること
- S3でバケットを公開せずHTTPSのみでサイトを公開する方法
- API Gateway を使用した Lambda関数 の呼び出し
- Javascript から Lambda関数 の呼び出し
- AWS WAFを使用した 特定のIPアドレスのリクエストからアクセス許可
この記事にないこと
- サイトページ・ゲームの作り方
- 各サービスの詳細な説明
やったことの流れ
- S3にフロントエンド(HTML, CSS)をデプロイ
- API Gateway でエンドポイントを作成
- Lambda でゲームロジックを実装
- WAF ACL を設定しアクセス許可するIPアドレスを設定
- CloudFront に AWS WAF を付与し IPアドレスのアクセス制限
- 画面の確認
1. S3にフロントエンド(HTML, CSS)をデプロイ
1-1. 静的コンテンツを作成する
HTMLを公開するためには「index.html」「error.html」のファイルが最低限必要です。
サンプルとしてファイルが必要な場合は以下を使用してください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="script.js" defer></script>
<title>Lambda Example</title>
</head>
<body>
<h1>Lambdaと連携したフォーム</h1>
<form id="myForm">
<label for="inputData">小文字を入力してください:</label>
<input type="text" id="inputData" name="inputData" required>
<button type="submit">送信</button>
</form>
<p id="response"></p>
<a href="error.html">エラーページへ</a>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Error</title>
</head>
<body>
<h1>エラーが発生しました</h1>
<a href="index.html">トップページに戻る</a>
</body>
</html>
1-2. S3バケットを作成する
S3はデータを格納・管理できるオブジェクトストレージサービスです。
S3を開き バケットを作成 から静的コンテンツを格納するバケットを作成。
バケット名 :任意で作成
その他の設定はそのままでOK
1-3. 作成したS3バケットに静的コンテンツをアップロードする
作成したバケットを開き、上述した「index.html」「error.html」をアップロードします。
画像のように出来ていればOKです!
2. Lambda でロジックを実装
今回はバックエンドも活用する動的サイトを作成するため、Lambda関数を作成します。
Lambdaを開き 関数の作成 から、以下の設定でロジックを実装します。
関数名 :任意で作成
ランタイム:実行したいコードに適した環境を選択
作成したLambda関数の コードソース にロジックを実装していきます。
サンプルとしてファイルが必要な場合は以下を使用してください。以下はNode.jsでの例です。
コードを更新する際は Deploy を押します。
export const handler = async (event) => {
// POSTされたデータを取得
const body = JSON.parse(event.body);
const inputData = body.data;
// データを大文字に変換する処理
const processedData = inputData.toUpperCase();
// レスポンスを返す
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*', // 必要なオリジンを設定
'Access-Control-Allow-Methods': 'GET, POST',
'Access-Control-Allow-Headers': 'Content-Type',
},
body: JSON.stringify({ message: `大文字変換: ${processedData}` }),
};
return response;
};
3. API Gateway でエンドポイントを作成
API Gatewayでフロントエンドとバックエンド(Lambda関数)をつなげ、ユーザーからのリクエストを受け付けられるようにします。
3-1. API Gateway を作成する
API Gateway のサービスから REST API を選択します
「API名」と「説明」は任意で、わかりやすいものをつけてください。
3-2. リソースを作成する
リソースの作成 からリソースの作成を行います。
「リソース名」を任意で設定します。
3-3. メソッドを作成する
作成したリソース(上記画像の場合: /testgame)を選択します。
メソッドを作成 から、以下の設定を行います。
・メソッドタイプ :POST
・統合タイプ :Lambda
・Lambda プロキシ統合:ON
・Lambda 関数 :🔍️マークから手順2で作成したLambda関数を選択
その他の設定はそのままでOK
3-4. CORSを作成する
作成したリソース(上記画像の場合: /testgame)を選択します。
CORSを有効にする から、以下の設定を行います。
Access-Control-Allow-Methods:「OPTIONS」と「POST」にチェック
Access-Control-Allow-Origin:「*」を指定します
他の設定はすべてそのままでOKです。
3-5. APIをデプロイする
APIをデプロイ から、以下の設定を行います。
ステージ :新しいステージ
ステージ名:任意のステージ名
デプロイが完了すると APIエンドポイント が生成されます。
このURL(APIエンドポイント)を介してフロントエンドからAPIにリクエストを送信できるようになります。
画像のような状態になっていればOKです!
3-5. APIをフロントエンドと連携する
フロントエンドとAPIを連携するようにJavaScriptのコードを作成します。
サンプルとしてファイルが必要な場合は以下を使用してください。
// APIエンドポイント(LambdaのAPI Gateway URL + API名)
const apiUrl = 'https://your-api-id.execute-api.your-region.amazonaws.com/prod/API名;
document.getElementById('myForm').addEventListener('submit', function(event) {
event.preventDefault();
var inputData = document.getElementById('inputData').value;
// LambdaをAPI Gateway経由で呼び出す
fetch(apiUrl, {
method: 'POST',
body: JSON.stringify({ data: inputData }),
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
document.getElementById('response').textContent = 'Lambdaレスポンス: ' + data.message;
})
.catch(error => {
document.getElementById('response').textContent = 'エラー: ' + error.message;
});
});
作成した「script.js」は手順1-3 と同様に「index.html」「error.html」と同じS3にアップロードしておきます。
4. WAF を設定しアクセス許可するIPアドレスを設定
4-1.IP sets を作成する
AWS WAF のメニューから IP sets を選択し、許可するIPアドレスを定義します。
リージョンを選択する箇所があるので「Global(CloudFront)」を選択し、
Create IP set から設定します。
許可したい環境のIPアドレスを指定します。
IP set name :任意で設定
IP addresses:許可したいIPアドレス(複数ある場合は改行区切り)
4-2.Web ACL を作成する
こちらもリージョンを選択する箇所があるので Global(CloudFront) を選択し、
Create web ACL から、以下の設定を行います。
Step 1 Describe web ACL and associate it to AWS resources
Resource type:Amazon CloudFront distributions
Name :任意のName
↓ Next
Step 2 Describe web ACL and associate it to AWS resources
Add rules から 「Add my own rules and rule groups」 を選択
Rule type:IP set
Rule :任意のNameを設定
IP set :手順4-1 で作成した IP sets を選択
Action :Allow(許可)を選択
↓ Add rule
ウェブ ACL のデフォルトアクション を Block にする
↓ Next
Step 3 Set rule priority
優先度は設定せず進みます。
↓ Next
Step 4 Configure metrics
メトリクスの設定も今回は設定せず進みます。
↓ Next
Step 5 Review and create web ACL
設定内容を確認し、OKなら Create web ACL でACLの設定を完了します。
5. CloudFront に AWS WAF を付与し IPアドレスの制限をかける
5-1. Distribution と OriginAccess を作成
CloudFront のサービスから ディストリビューション を選択し
CloudFront ディストリビューションを作成 から以下の設定を行う。
オリジン(Origin)
Origin domain:作成したS3を選択
名前(Origin ID):自動で生成
オリジンアクセス:Origin access control settings (recommended)
> Create new OAC 設定はそのまま Create
Enable Origin Shield:いいえ
WAF
セキュリティ保護を有効にする
> 既存の WAF 設定を使用
> 手順4 で作成した ACL を選択
設定(Settings)
デフォルトルートオブジェクト:S3にアップロードしたメインページの html
5-2. S3バケットポリシーの設定
自動で作成された バケットポリシー をコピーし、S3 の バケットポリシーに設定します。
作成したディストリビューションの オリジン からコピー出来ます。
手順1で作成した S3 に移動し、
アクセス許可 から バケットポリシー を 編集 します。
コピーしたポリシー をそのまま貼り付ければOKです。
6. 画面の確認
6-1. 画面を確認してみよう
これですべての設定が完了です!
実際にサイトにアクセスしてみましょう!
サイトのURLは CloudFront の 作成したディストリビューション に設定されている
ディストリビューションドメイン名 をコピーしたものです。
サンプルで作成した場合、以下の画面が表示されていれば成功です!
「送信」を押すと Lamuda で構築した大文字変換のロジックが実行されます。
6-2. アクセス拒否を確認してみよう
手順4-1 で設定したIPアドレス以外で同じURLにアクセスするとどうなるかも確認してみましょう。
設定したIPアドレス以外でアクセスをすると403エラーが表示されます。
さいごに
おつかれさまでした!
アクセス制限のある簡易的な動的サイトを作成する方法について記しました。
AWSにはじめて触れた自分のための備忘録になりますので、誤り等ありましたらご指摘ください。
もし誰かのお役に立てれば幸いです、ご清覧ありがとうございました。
参考
■ S3 + CloudFront + WAF ACL について
https://qiita.com/polarbear08/items/84b7add0ddd309abda74
https://qiita.com/sugimount-a/items/8b4fad021a12d520f210
■ キャッシュ削除について
https://zenn.dev/collabostyle/articles/3e7866de979682
おまけ
API Gateway の REST API に対してリソースポリシーでアクセス制限かけれたらしいです。
こっちのがシンプルだったかも。
Discussion