はじめに
AWSの学習を進める中で、「S3 → CloudFront → WAF」という王道の静的サイト配信構成に挑戦しました。
一見シンプルに見えるこの構成ですが、実際にやってみるとUIの変更、IPv6の挙動、OACの仕組み、WAFの設定方法など、多くの学びと壁にぶつかりました。
この記事では、実際に手を動かして気づいたリアルな問題点と解決方法を詳しく記録します。同じくAWSを学んでいる方の参考になれば幸いです。
ハンズオンの目的と構成
何を作るのか
IP制限付きの静的Webサイト配信基盤
- S3バケットにHTMLファイルを配置
- CloudFrontでグローバル配信
- WAFで特定IPのみアクセス許可
なぜこの構成なのか
実務でよく使われる構成で、以下の実践的スキルが身につきます:
- S3静的ホスティング:Webサイトのホスティング基盤
- CloudFront + OAC:CDN配信とセキュアなアクセス制御
- WAF:IPベースのアクセス制限
- IPv4/IPv6:デュアルスタック環境の理解
前提知識
必要なAWS知識
- S3の基本操作(バケット作成、ファイルアップロード)
- CloudFrontの概要理解
- WAFの基本概念
料金について
- S3:ストレージ容量と転送量に応じた従量課金
- CloudFront:データ転送量に応じた従量課金
- WAF:Web ACL $5/月 + ルール $1/月 ≈ $6/月
⚠️ 注意:WAFは少額ですが継続課金されるため、検証後は削除を推奨します。
実施手順
ステップ1: S3バケット作成と静的ホスティング
1-1. S3バケット作成
- S3コンソール → 「バケット作成」
- バケット名:グローバルで一意な名前(例:
my-website-bucket-202412) - リージョン:ap-northeast-1(東京)
- その他はデフォルト設定でOK
1-2. index.htmlを作成してアップロード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AWSハンズオン - S3静的サイト</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 50px auto;
padding: 20px;
background-color: #f0f0f0;
}
.container {
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1 {
color: #232F3E;
}
.status {
color: #16A34A;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container">
<h1>🚀 AWSハンズオン環境</h1>
<p class="status">✓ S3静的ホスティング動作中</p>
<p>このページはAmazon S3上でホストされています。</p>
<hr>
<p><strong>実施日:</strong> 2024年12月</p>
<p><strong>構成:</strong> S3 → CloudFront → WAF</p>
</div>
</body>
</html>S3バケットにアップロード。
1-3. 静的ホスティング有効化(一時的)
- バケット → プロパティ → 静的ウェブサイトホスティング
- 有効化 → インデックスドキュメント:
index.html - パブリックアクセスのブロック設定を解除
- アクセス許可 → 「パブリックアクセスをすべてブロック」のチェックを外す
- バケットポリシーを追加:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::あなたのバケット名/*"
}
]
}- 静的ホスティングのURLでアクセス確認
ステップ2: CloudFront設定(OAC使用)
2-1. 静的ホスティングを無効化
CloudFront経由のアクセスのみ許可するため:
- S3 → プロパティ → 静的ウェブサイトホスティング → 無効化
2-2. CloudFrontディストリビューション作成
旧UIでの手順(新UIは後述の注意点参照):
- CloudFrontコンソール → 「Create distribution」
Step 1: Choose a plan
- そのまま「Next」
Step 2: Get started
- Distribution name:
handson-static-site - Description:
S3静的サイト配信用 - そのまま「Next」
Step 3: Specify origin
- Origin type:Amazon S3
- S3 origin:作成したS3バケットを選択
- Origin path:空欄
- オリジン設定:Use recommended origin settings
- Cache settings:Use recommended cache settings
- そのまま「Next」
Step 4: Enable security
- 何も選択せず「Next」(⚠️ 重要)
Step 5: Review and create
- Default root object:
index.html← 必須! - 「Create distribution」
2-3. S3バケットポリシー更新
CloudFront作成後、表示されるバケットポリシーをコピー:
{
"Version": "2012-10-17",
"Statement": {
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::バケット名/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::アカウントID:distribution/ディストリビューションID"
}
}
}
}- S3 → アクセス許可 → バケットポリシー
- コピーしたポリシーを貼り付けて保存
- パブリックアクセスのブロックを再度有効化
2-4. 動作確認
- デプロイ完了を待つ(5〜15分)
- CloudFrontドメイン(
xxxxx.cloudfront.net)でアクセス - S3エンドポイントでアクセスできないことを確認
ステップ3: WAF設定
3-1. 自分のIPアドレスを確認
- https://www.ugtop.com/spill.shtml でIPアドレスを確認
- 例:
203.0.113.1
3-2. IP Setの作成(IPv4)
- WAFコンソール → IP sets → Create IP set
設定内容:
- IP set name:
allowed-my-ip - Region:Global (CloudFront)
- IP version:IPv4
- IP addresses:
203.0.113.1/32※ 末尾の
/32は必須
- Create IP set
3-3. Web ACL作成(旧UI)
- WAFコンソール → Web ACLs → Create web ACL
Step 1: Describe web ACL
- Name:
cloudfront-web-acl - Description:
CloudFront用のアクセス制御 - CloudFront distributions:作成したディストリビューションを選択
- 「Next」
Step 2: Add rules and rule groups
- 「Add rules」→「Add my own rules and rule groups」→「Rule builder」
ルール設定:
- Name:
allow-my-ip-rule - Type:Regular rule
- If a request:matches the statement
- Inspect:Originates from an IP address in
- IP set:
allowed-my-ip - IP address to use:Source IP address
- Action:Allow
「Add rule」→「Next」
Step 3: Set rule priority
- そのまま「Next」
Step 4: Configure metrics
- そのまま「Next」
Step 5: Review and create
- Default action:Block ← 重要!
- 「Create web ACL」
3-4. 動作確認
- 自分のPC(許可したIP):CloudFrontドメインにアクセス → ✅ 表示される
- スマホ4G/5G:CloudFrontドメインにアクセス → ❌ 403エラー
つまづいたポイントと解決方法
問題1: WAFのUI変更で手順が分からない
症状:
- 新UIと旧UIが混在している
- 手順通りに設定できない
解決方法:
- WAFコンソール左下の**「Switch to AWS WAF Classic」**で旧UIに切り替え
- 旧UIの方が手順が明確
学び:
- AWSのUIは頻繁に更新される
- 古い記事の手順は現在のUIと異なる可能性がある
問題2: CloudFrontでセキュリティプランが自動有効化される
症状:
Failed to associate web ACL with CloudFront distribution:
You can't remove or replace the web ACL for your distribution.原因:
- CloudFront作成時の「Enable security」ステップで自動的にセキュリティプランが有効化
- このプランがあるとWeb ACLの付け替えができない
解決方法:
方法1:既存のWeb ACLを編集(推奨)
- 自動作成された
CreatedByCloudFront-xxxxxを編集 - IP許可ルールを追加
- デフォルトアクションをBlockに変更
方法2:CloudFrontを作り直す
- 「Enable security」ステップで何も選択しない
- その後、自分で作成したWeb ACLを紐付ける
学び:
- CloudFrontの自動セキュリティ機能に注意
- 既存リソースの有効活用も選択肢
問題3: IPv6でアクセスされてIPv4ルールが効かない
症状:
- IPv4のIPアドレスでIP Setを作成
- しかし自宅PCからはアクセスできない
- WAFログを見ると
2404:7a81:...というIPv6アドレスでアクセスされている
原因:
- CloudFrontはデフォルトでIPv6が有効
- 自宅のインターネット環境がIPv6対応
- → IPv6が優先的に使用される
解決方法:
方法1:IPv6用のIP Setとルールを追加
IPv6用IP Setを作成:
- Name:
allowed-my-ipv6 - IP version:IPv6
- IP addresses:
2404:7a81:1fc0:4600:29d1:2c51:57:941a/128
※ IPv6の場合、末尾は/128
- Name:
IPv6許可ルールを追加:
- 既存のWeb ACLに新しいルールを追加
- IP Set:
allowed-my-ipv6を使用
方法2:CloudFrontでIPv6を無効化
- CloudFront → ディストリビューション → General → Edit
- 「IPv6」のチェックを外す
- Save changes
- デプロイ完了を待つ
実際のIPアドレスを確認する方法:
- 一時的にWeb ACLのデフォルトアクションを「Allow」に変更
- 自宅PCからアクセス
- WAF → Web ACL → Sampled requests タブ
- AllowされたリクエストのSource IPを確認
- そのIPをIP Setに追加
- デフォルトアクションを「Block」に戻す
学び:
- IPv4とIPv6は別物
- 現代のインターネット環境ではIPv6が普及している
- 自宅と会社で接続方式が異なることもある
問題4: ファイル更新がCloudFrontに反映されない
症状:
- S3上のindex.htmlを更新
- CloudFrontドメインにアクセスしても古いまま
- ブラウザのキャッシュクリアをしても変わらない
原因:
- CloudFrontがファイルをキャッシュしている
- ブラウザのキャッシュクリア ≠ CloudFrontのキャッシュクリア
解決方法:Invalidation(キャッシュ無効化)
- CloudFront → ディストリビューション → Invalidations タブ
- 「Create invalidation」
- Object paths:
/index.htmlまたは全ファイル:
/* - 「Create invalidation」
- ステータスが「Completed」になるまで待つ(1〜3分)
- ブラウザでハードリロード(Ctrl+F5 / Cmd+Shift+R)
学び:
- CloudFrontはデフォルトで24時間キャッシュする
- 開発中は頻繁にInvalidationが必要
- 本番環境では適切なキャッシュTTL設定が重要
問題5: 自宅のIPアドレスが特定できない
症状:
- 確認くんサイトのIPアドレスでは制限が効かない
- ルーターの管理画面のIPアドレスでも効かない
原因:
- 複雑なネットワーク環境(プロバイダのNAT、VPN等)
- IPv4とIPv6の混在
- CloudFrontが受け取るIPと、確認くんで見えるIPが異なる
解決方法:実際のアクセスログから確認
手順:
- Web ACLのデフォルトアクションを一時的に「Allow」に変更
- 自宅PCからCloudFrontにアクセス
- WAF → Sampled requests タブ
- 「Allow」されたリクエストを探す
- Source IPに表示されているのが実際のIPアドレス
- そのIPをIP Setに追加
- デフォルトアクションを「Block」に戻す
学び:
- 理論と実際は異なることがある
- ログを見て実際の挙動を確認することが重要
- ネットワークの仕組みは複雑
まとめ
構成のおさらい
[インターネット]
↓
[WAF] ← IP制限
↓
[CloudFront] ← CDN配信 + OAC
↓
[S3バケット] ← HTMLファイル学んだこと
技術面
OAC(Origin Access Control)
- CloudFrontからS3への安全なアクセス制御
- 旧方式のOAI(Origin Access Identity)より推奨
WAFのルール優先度
- Allowルールを先に評価
- デフォルトアクションでBlock
- この組み合わせで「特定IPのみ許可」を実現
IPv4とIPv6の共存
- 両方に対応する必要性
- 実際のアクセスログでの確認が確実
CloudFrontのキャッシュ
- Invalidationの仕組み
- 開発時と本番運用での考慮点
心構え
ドキュメント通りにいかないこと前提
- UIの変更
- 環境の違い
- → 柔軟な対応が必要
ログを見る習慣
- エラーメッセージを丁寧に読む
- Sampled requestsで実際の挙動を確認
- 推測より実測
小さく試して確認
- いきなり全部設定しない
- 1ステップずつ動作確認
- 問題の切り分けが容易に
次のステップ
このハンズオンができたら、次は以下に挑戦してみてください:
応用編
S3バケットポリシーの強化
- 特定IPからの操作のみ許可
- OACとIPベースの二重制限
自動デプロイの構築
- 開発S3 → 本番S3へのデプロイ
- CodeBuild/Lambda + EventBridge
CloudFrontのキャッシュ最適化
- キャッシュポリシーの設定
- 画像・動画の最適化
別の学習テーマ
- Route 53で独自ドメイン設定
- ACMでHTTPS化
- Lambda@Edgeで動的処理追加
参考リソース
公式ドキュメント
便利ツール
- 確認くん:IPアドレス確認
おわりに
一見シンプルな構成でも、実際に手を動かすと多くの学びがありました。
特にIPv6の挙動やCloudFrontのセキュリティプランなど、ドキュメントだけでは気づきにくいポイントに直面しました。
これからAWSを学ぶ方の参考になれば嬉しいです。
トラブルは最高の教材です。
一つひとつ解決していく過程で、確実にスキルが身につきます。
ぜひ実際に手を動かして、自分なりの学びを得てください!
タグ:#AWS #S3 #CloudFront #WAF #ハンズオン #初心者向け
この記事が役に立ったら、ぜひシェアやコメントをお願いします!
コメント