CONTACT
お問い合わせ

AWS WAFの活用

目次

  • 導入方法
  • 設定ルールについて
  • 接続元IP / 国の制御方法
  • ログの保管先
  • ログの読み方

導入方法

AWS WAFの導入は、ステップとしては大きく2段階になります。
1.保護パックの作成
2.保護パックへのリソース割り当て
です。

保護パックの作成

保護パックとは、簡単に言うと適用するWAFのルールをまとめたセットです。
どの国からのアクセスを許可する、どんな攻撃パターンを検知したらブロックする、といったルールを設定します。

「WAF & Shield」のページを開きます。

「保護パックを作成」というボタンを押します。

ここで保護対象のリソースを選択して作成することができます。

設定するルールについて、推奨セットも用意されており、ここから選択することもできます。
※保護パックはリソースを紐づけていなくても存在するだけで課金が発生します。作成前に料金(https://aws.amazon.com/jp/waf/pricing/)を確認しておきましょう。

保護パックへのリソース割り当て

リソースの割り当てには大きく3つの方法があります。
1.作成時の「保護するリソース」を選択する方法。こちらは上記の画面から設定する場合です。
2.保護対象のリソースの「統合」タブから保護パックを選択する方法。以下の画像はロードバランサーの場合です。「WAFリソースを関連付ける」というボタンから設定できます。

3.作成した保護パックの編集画面からリソースを選択する方法。「リソースを管理」から設定ができます。

どの方法で設定しても違いはありません。
1つの保護パックに対してリソースは好きなだけ設定できます。保護パックは存在するだけで固定費がかかるため、基本的には1つの保護パックに対して多くのリソースに紐づけておいた方がお得です。(※ただしリクエスト量に応じた従量課金もあるので注意)

設定ルールについて

上記で述べた通り、推奨セットは用意されていますが、もちろん自分でルールを選択して構築することもできます。
ルールにはいくつか種類があります。

  • 「AWSマネージドルールグループ」は、AWSが提供している基本的なルールセットです。有料のものもありますが、基本的なところは無料です。
  • 「AWS Marketplace ルールグループ」は、有料のルールセットです。使用のためには別途お金がかかります。
  • 「カスタムルール」は、自前でルールを設定することができます。特定の国やIPの許可にはこちらが必要になります。自分で作るので無料です。
  • 「カスタムルールグループ」は、自分でルールセットを作れる機能です。例えば保護パックを複数作るといった場合に、カスタムルールグループを作成しておけば同じルールを簡単に使いまわせます。

基本的にはまず「AWSマネージドルールグループ」から必要なルールを選択し、その上で追加で欲しいルールを「カスタムルール」で作成する、という流れになるかと思います。
以下が「AWSマネージドルールグループ」です。キャパシティと書いてあるものは簡単に言うとルールコストです。この合計が1500を超えると追加料金が必要になります。1500に収まるように調整しましょう。

各ルールの詳細は公式サイト(https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/aws-managed-rule-groups-list.html)をご確認ください。

また、上記はルールグループです。グループということはつまり、この中には細かいルールが色々とセットになっています。
例えば、「Anonymous IP list」の中には「AnonymousIPList」と「HostingProviderIPList」という2つのルールが含有されており、ルール単位でアクションの設定が可能です。

ルールに設定できるアクション

ここで言うアクションとはつまり、そのルールに合致した場合のアクセスをどう扱うか?です。
設定できるアクションは以下の5つです。

  • Block:その名の通りです。アクセスを拒否します。
  • Challenge:JavaScriptが正常に動くかを確認した上でアクセスを許可します。bot避けです。CAPTCHAと違って、ユーザに操作を要求しません。
  • CAPTCHA:よくある「ロボットではありませんチェック」です。信号機の画像を選択してください、みたいなのに成功すればアクセスを許可します。
  • Count:ログに記録した上で、スルーします。ルールグループ内でこのルールだけ無効化したい、みたいな場合に設定することが多いです。
  • Allow:問題なしとして合致した時点でアクセスを許可します。後続チェックをすべてスキップするので、基本的にカスタムルールでしか使いません。

ちなみにMonetizeという6つ目の選択肢は、料金を請求した上でアクセスを許可できるようです。つい最近(2026年6月)追加されたようです。

接続元IP / 国の制御方法

接続元IP/国の制御にはカスタムルールが必要になります。
「カスタムルール」を選択すると、まさにその通りの選択肢が表示されます。

例えば「IPベースのルール」を選択すると以下のような画面に遷移します。
国であれば「地域ベースのルール」を選択すれば良いです。
UIがわかりやすいので細かい説明は割愛します。

カスタムルールでは上記だけでなく、リクエストボディやクエリ文字列、Cookieなども見ることができます。サイズチェックや文字列の一致はもちろん、正規表現を用いてのチェックも可能です。
AND条件、OR条件、NOT条件も設定できるので、割と自由度高く設定ができるのではないでしょうか。

カスタムルールも複雑さに応じてキャパシティが設定されます。合計値には気をつけましょう。
とはいえ「日本国内からのアクセスを許可する」程度であれば、キャパシティは1です。誤差ですね。

ログの保管先

ログの保管先にはCloudWatch Logs、Amazon S3、Firehoseが選択できます。
例えばS3に保管した場合には、以下のようなフォルダ構成でgz形式のファイルが保存されます。

[BucketName]/[TopFolder]/[AccountID]/WAFLogs/[Region]/[WebACLName]/2026/04/02/02/10/

上記であれば2026年4月2日2時10分~14分のログが出力されるフォルダです。5分単位で別のフォルダが作成されます。
ちなみに2時10分は日本時間ではなくUTCです。
1日あたり、00時00分~23時55分までのフォルダが作成されます。

WAFのログは保護パックが処理したアクセスのログです。つまり何が言いたいかというと、割り当てたリソースごとに出力先を分ける、みたいなことはできません。
ただログの中身を見れば手がかりはあります。例えばロードバランサーであれば、”httpSourceId”の値からリソースを区別することができます。

ログの読み方

以下が実際に出るログの例です。(※セキュリティを考慮してマスクはしています)
見やすいように改行も入れて整形していますが、このようなjsonが1行で出てきます。

{
	"timestamp": 1747356070337,
	"formatVersion": 1,
	"webaclId": "arn:aws:wafv2:xxxxxx",
	"terminatingRuleId": "AWS-AWSManagedRulesCommonRuleSet",
	"terminatingRuleType": "MANAGED_RULE_GROUP",
	"action": "BLOCK",
	"terminatingRuleMatchDetails": [],
	"httpSourceName": "ALB",
	"httpSourceId": "xxxxxxxx",
	"ruleGroupList": [
		{
			"ruleGroupId": "AWS#AWSManagedRulesAdminProtectionRuleSet",
			"terminatingRule": null,
			"nonTerminatingMatchingRules": [],
			"excludedRules": null,
			"customerConfig": null
		},
		{
			"ruleGroupId": "AWS#AWSManagedRulesAmazonIpReputationList",
			"terminatingRule": null,
			"nonTerminatingMatchingRules": [],
			"excludedRules": null,
			"customerConfig": null
		},
		{
			"ruleGroupId": "AWS#AWSManagedRulesAnonymousIpList",
			"terminatingRule": null,
			"nonTerminatingMatchingRules": [],
			"excludedRules": null,
			"customerConfig": null
		},
		{
			"ruleGroupId": "AWS#AWSManagedRulesCommonRuleSet",
			"terminatingRule": {
				"ruleId": "NoUserAgent_HEADER",
				"action": "BLOCK",
				"ruleMatchDetails": null
			},
			"nonTerminatingMatchingRules": [],
			"excludedRules": null,
			"customerConfig": null
		}
	],
	"rateBasedRuleList": [],
	"nonTerminatingMatchingRules": [],
	"requestHeadersInserted": null,
	"responseCodeSent": null,
	"httpRequest": {
		"clientIp": "xx.xxx.xxx.x",
		"country": "JP",
		"headers": [
			{
				"name": "Host",
				"value": "xx.xxx.xxx.xxx"
			},
			{
				"name": "Connection",
				"value": "Upgrade"
			},
			{
				"name": "Upgrade",
				"value": "websocket"
			},
			{
				"name": "Sec-WebSocket-Version",
				"value": "13"
			},
			{
				"name": "Sec-WebSocket-Key",
				"value": "xxxxxxxxxxxxxxx"
			},
			{
				"name": "x-mbx-apikey",
				"value": "xxxxxxxxxxxxxxx"
			}
		],
		"uri": "/ws/btcusdt@bestBidAsk",
		"args": "",
		"httpVersion": "HTTP/1.1",
		"httpMethod": "GET",
		"requestId": "xxxxxxxxxxx",
		"fragment": "",
		"scheme": "https",
		"host": "xx.xxx.xxx.xxx"
	},
	"labels": [
		{
			"name": "awswaf:managed:aws:core-rule-set:NoUserAgent_Header"
		}
	],
	"ja3Fingerprint": "xxxxxxxxxxx",
	"ja4Fingerprint": "xxxxxxxxxxx"
}

代表的なところをいくつか紹介します。
“timestamp”:UNIXタイムスタンプで出てきます。
“terminatingRuleId”:terminatingという名前の通り終了ルールです。どのルールでブロックされたのか、どのルールで許可されたのかと言ったことがわかります。ルールグループならルールグループの名前が出てきます。カスタムルールであればカスタムルールの名前が出てきます。
“action”:最終的なアクションです。許可したなら”ALLOW”、ブロックしたなら”BLOCK”が出てきます。結果が出るので、検証続行するCOUNTは出ません。
“ruleGroupList”:検証したルールグループです。ルールグループです。なので、カスタムルールは含まれません。グループではないので。どこかのルールに一致してブロックという結論が出た場合は、それ以降のルールは検証しないため、出てきません。
“ruleGroupList”の下にある”terminatingRule”:これが実際の終了ルールです。上記の例で言うと「”AWS-AWSManagedRulesCommonRuleSet”というルールグループに含まれる”NoUserAgent_HEADER”というルールに合致したためブロックした」ということがわかります。
“ruleGroupList”の下にある”nonTerminatingMatchingRules”:合致したけど終了ではない場合、こちらに入ります。具体的に言うとCountの場合はここに記録されます。