この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
AWS WAFのレートベースルールを使うと、5分間にしきい値を超える接続があったIPアドレスからの接続をブロックできます。接続が落ち着くと拒否リストから削除され、接続できるようになります。レートベースルールでブロックしたIPをIP Setsに登録し、ずっと接続をブロックする仕組みを作ったので、紹介します。レートベースルールでブロックしたIPは「aws wafv2 get-rate-based-statement-managed-keys」コマンドで取得できます。Lambdaを定期的に起動し、取得したIPアドレスをIP Setルールに登録します。
ルールの作成
Web ACLにIP SetとRate-baseのルールを作成します。IP Setルールのプライオリティを高くし、先に評価されるようにします。Actionはそれぞれブロックとします。
Name | Action | Priority |
---|---|---|
IPset | Block | 0 |
Rate-base | Block | 1 |
Lambdaの作成
コードはGithubをご覧ください。Python 3.8で動作確認しました。update_ip_setでIP setを更新するのですが、変更内容だけを指定するのではなく、GetIPSetで完全なIPリストを取得し、update_ip_setする必要がありました。変更内容だけを指定してupdate_ip_setをすると、指定したIPアドレスだけのIP Setになるので注意が必要でした。
IAMポリシーとして、以下を設定し、LambdaのIAMロールに割り当てます。レートベースルールでブロックしたIPの取得と、IP Setの取得、更新を許可しています。Arnは環境に合わせて変更してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"wafv2:GetRateBasedStatementManagedKeys",
"wafv2:GetIPSet",
"wafv2:UpdateIPSet"
],
"Resource": [
"arn:aws:wafv2:ap-northeast-1:123456789:regional/ipset/IPSETNAME/12345-1234-1234-1234-1234abcdefghijk",
"arn:aws:wafv2:ap-northeast-1:123456789:regional/webacl/ACLNAME/12345-1234-1234-1234-1234abcdefghijk"
]
}
]
}
レートベースルールで検知したイベント駆動でLambdaを起動したかったのですが、できないようでしたのでEvent Bridgeで「rate(1 minute)」と毎分起動することにしました。もう少し頻度を落としてもいいと思います。
動作テスト
Amazon Linux 2をパブリックサブネットで起動し、IAMロールに「AmazonSSMManagedInstanceCore」ポリシーを割り当てます。Systems ManagerのRum CommandのAWS-RunShellScriptで以下を実行しEC2からAWS WAFを割り当てたALBに150回接続しました。レートベースルールのしきい値は100の環境です。
#!/bin/sh
URL="http://alb-name.ap-northeast-1.elb.amazonaws.com/";
HEAD="Content-Type:text/xml";
for i in {0..150}
do
curl -H $HEAD $URL
echo ""
echo ${i}
sleep 0.1
done
IP SetにEC2のPublic IPが登録されていれば成功です。
5つのIPをレートベースルールでブロックした環境では、CloudWatch Logsに以下のようにログが残りました。
The IPs detected by the rate-based rule are as follows
['xxx.xxx.xxx.xxx/32', 'xxx.xxx.xxx.xxx/32', 'xxx.xxx.xxx.xxx/32', 'xxx.xxx.xxx.xxx/32', 'xxx.xxx.xxx.xxx/32']
The current IP Sets are as follows
['xxx.xxx.xxx.xxx/32', 'xxx.xxx.xxx.xxx/32', 'xxx.xxx.xxx.xxx/32', 'xxx.xxx.xxx.xxx/32', 'xxx.xxx.xxx.xxx/32','xxx.xxx.xxx.xxx/32', 'xxx.xxx.xxx.xxx/32', 'xxx.xxx.xxx.xxx/32', 'xxx.xxx.xxx.xxx/32', 'xxx.xxx.xxx.xxx/32']
Add xxx.xxx.xxx.xxx/32 to the IP set
Add xxx.xxx.xxx.xxx/32 to the IP set
Add xxx.xxx.xxx.xxx/32 to the IP set
Add xxx.xxx.xxx.xxx/32 to the IP set
Add xxx.xxx.xxx.xxx/32 to the IP set
Addition to the IP set is complete.
キャリアがNATしているケースのように1つのグローバルIPを共有している環境では、関係ないユーザーもブロックしてしまうケースも考えられるため、本仕組みのデメリットも理解した上で使っていただければと思います。