How to set up a rate-based rule in AWS WAF
This is an English translated version of the following article.
Question
I have been experiencing a DDoS attack on our service for several days. In the attack, hackers use hundreds of spoofed IP addresses. How can I automatically add the IP addresses to a blocklist?
Solution
You can set up a rate-based rule in AWS WAF. Alternatively, you could use AWS WAF Security Automations for fine-grained controls.
What is a rate-based rule in AWS WAF?
Once you set a rate-based rule, AWS WAF counts the number of source IP addresses requests and blocks the IPs automatically if their numbers exceed a threshold value you specified. As of now, the minimum threshold is 100 requests per 5 minutes.
How to make a Web ACL and a rate-based rule
On AWS WAF console page, click "Create web ACL".
You need to input details of the web ACL. At first, you choose the name of the web ACL(CloudWatch Metric name will be automatically added as the same name). Then, for Resource Type, select an option you would like to associate with this web ACL.
At this time, I selected "Regional resources" for ALB in the Oregon region. Also, I chose "US West(Oregon)" as the region.
Next, you need to choose associated AWS resources. Click "Add AWS resources".
After choosing "Application Load Balancer", check a box next to the ALB you would like to associate with the web ACL. Then click "Add" and "Next".
For the next step, set up a rule. Choose "Add my own rules and rule groups".
As a rule type, select "Rule Builder". Name the rule and choose "Rate-based rule" as the type.
About this time, I set "100" for the rate limit in order to be blocked more than 100 accesses per 5 minutes and chose "source IP address" as the IP address to use for rate limiting. Also, chose "Only consider requests that match the criteria in a rule statement" since I would like to set this rule for the path "/admin".
Then, configure a statement. Choose "matches the statement" to be matched only the statement. After that, select "URI path" as the inspect and "Starts with string" as the match type. The string to match is set "/admin" that I mentioned above.
Choose "Block" action and click "Add rule".
On the next page, the capacity to be used by this rate-based rule is shown. For this rule, it's "4". Set the default web ACL action for requests that don't match any rules to "Allow" and click "Next".
After that, you can set rule priority, but there is only one rule so click "Next".
Then, configure metrics. If needed, you can change the corresponding CloudWatch metric name. Also, there is an option to show sampled requests matched with the rule on WAF console. Choose "Enable sampled requests" this time.
Finally, review every configuration. Click "Create web ACL" if it is acceptable. Once Web ACL is created, test if the rate-based rule works fine without any issues.
Test the rate-based rule
Launch a Linux EC2 instance on Tokyo region and connect to the instance using SSH. Then, run curl command on the instance to the ALB associated with the WAF. I confirmed that 200 OK was returned as follows.
$ curl -I http://ttttt-403999499.us-west-2.elb.amazonaws.com/admin/ HTTP/1.1 200 OK Date: Thu, 20 May 2021 17:43:16 GMT Content-Type: text/html;charset=ISO-8859-1 Connection: keep-alive Server: Apache/2.4.46 () Upgrade: h2,h2c
Next, send 200 requests to the ALB using ApacheBench. For the first attempt, no request was not blocked, as you can see.
$ ab -n 200 -c 1 http://ttttt-403999499.us-west-2.elb.amazonaws.com/admin/ (Omitted) Complete requests: 200 Failed requests: 0 Total transferred: 209851 bytes
Right after the attempt, I executed the same command again. 187 requests were blocked as a result.
$ ab -n 200 -c 1 http://ttttt-403999499.us-west-2.elb.amazonaws.com/admin/ (Omitted) Complete requests: 200 Failed requests: 187 (Connect: 0, Receive: 0, Length: 187, Exceptions: 0) Non-2xx responses: 187
For the third test, All requests were blocked successfully!
$ ab -n 200 -c 1 http://ttttt-403999499.us-west-2.elb.amazonaws.com/admin/ (Omitted) Complete requests: 200 Failed requests: 0 Non-2xx responses: 200
I executed the curl command again from the EC2 instance and confirmed 403 error was returned.
$ curl -I http://ttttt-403999499.us-west-2.elb.amazonaws.com/admin/ HTTP/1.1 403 Forbidden Server: awselb/2.0 Date: Thu, 20 May 2021 17:50:11 GMT Content-Type: text/html Content-Length: 118 Connection: keep-alive
You can see which IP address is blocked by the rate-based rule using AWS CLI get-rate-based-statement-managed-keys
command as follows.
Set "REGIONAL" as scope since Web ACL is associated with ALB. Then, input other options and run the command.
$ aws wafv2 get-rate-based-statement-managed-keys \ --scope REGIONAL \ --web-acl-name waf0512 \ --web-acl-id b0171f79-7455-4533-94fd-e2463392512f \ --rule-name Rate-based-rule-with-address { "ManagedKeysIPV4": { "IPAddressVersion": "IPV4", "Addresses": [ "13.113.177.16/32" ] }, "ManagedKeysIPV6": { "IPAddressVersion": "IPV6", "Addresses": [] } }
After a certain time, I ran get-rate-based-statement-managed-keys
command again. The IP address was released from the denylist.