Protecting your AWS ALB from DDoS attacks by using AWS WAF
Distributed denial of service (DDoS) attacks are a constant threat in today’s digital landscape, capable of breaching web applications and services. AWS provides robust tools to mitigate these threats, including the AWS Web Application Firewall (WAF). In this article, we will explore how to use AWS WAF to protect your Application Load Balancer (ALB) from DDoS attacks.
Prerequisites
Before you begin, ensure that you have the following set up:
- AWS Account: An active AWS account with appropriate permissions to create and manage AWS WAF, ALB, and EC2 resources.
- Application Load Balancer (ALB): A configured ALB with target groups (TG) that routes traffic to your backend instances.
- EC2 Instances with Nodejs App: Running Nodejs App on EC2 instances as the backend for your ALB.
- Basic Knowledge of AWS: Familiarity with the AWS Management Console and basic AWS services.
Setup your ALB with target group and app server running on EC2 instance.
Step 1: Start the EC2 instances:
- Select a name for your instances, number of nodes to spin up and select Amazon Machine Image (AMI) and instance type.
- Configure instance information, ensure to create key-pair(to use for ssh), add storage, and configure security groups to allow HTTP/HTTPS traffic.
- Launch instance
- Connect to your instance via ssh
# ensure you have the right permisions for your downloaded key pairs we will use
# chmod 600 for read and write.
sudo chmod 600 path-to-your-key-file/key-file.pem
# ssh into your instance, for this copy the public IP from the instance details,
# username will be the default user for aws ec2 (ec2-user)
ssh -i path-to-your-key-file/key-file.pem ec2-user@your-instance-ip
- We will use a simple express app for demonstration you can clone the repo here
Update and install Docker
sudo apt-get update
sudo apt-get install -y docker.io
sudo usermod -aG docker $USER
# once done with this log out and log back in or simply run newgrp docker to
# apply the new group membershipt without logging out.
Start the docker Container
- The cloned code above already contains a Dockerfile and ready to build the image and start the container instantly.
#Execute following commands to build the image and run the container
cd recipe-app # navigate to the recipe app dir
docker build -t recipe-app . # build docker image
docker run -d -p 80:3000 recipe-app # start the container binding container port 3000 into host port 80
Copy your public IP into a browser hitting the root /
will return the healthy status message and this means our app is up and running 👌
If you hit the /recipes
endpoint you will get the below response
summary of the steps so far:
1.Launch an Ubuntu EC2 instance.
2.SSH into the instance and install Docker.
3.Clone recipe app.
4.Build and run the Docker container on port 80.
5.Access your app via the EC2 instance's public IP.
NEXT
Step 2: Create a Target Group
- Choose a target type -> Instance
- Target group name ( your target group name)
- Protocol : Port [http: 80]
- IP address type [ipv4]
- VPC -> select your vpc
- ProtocolVersion->HTTP1
- Health Checks:
Health Check protocol: HTTP
Path: ‘/’ - Select Instance to register as target for the target group
Leave everything else as default
Click Next >>
Step 3: Create an Application Load Balancer
Navigate to the EC2 Dashboard and select “Load Balancers” under “Load Balancing”
- Choose Application Load balancer
- Configure basic settings, including load balancer name, scheme [internet facing], and IP address type[IPV4].
- Select A VPC for your targets, you have an option of using an existing or Creating a new one, we will use an existing VPC, It is important to note only VPC’s with IGW will be available for selection.
- Configure AZ’s Mapping it is recommended to use atleast two availabillity zones and for our case we will use es-east-1a and us-east-1b please feel free to use any other zone of your choice.
- Configure Security groups, Ensure the ALB security has an ingress rule for port 80 and 443, we will allow connection from any source.
- Configure listeners and routing by adding the target group created earlier.
- Review and create the ALB.
Congrats you have created your alb 🐡
Understanding DDoS Attacks
Multiple systems compromised in a DDoS attack flood the target with traffic, making it unusable. These attacks can vary in nature and may include:
- Volumetric attacks: Overwhelm bandwidth on the target.
- Protocol attacks: Exploit vulnerabilities in network protocols.
- Application layer attacks: Target specific vulnerable web applications.
AWS WAF: The First Line of Defense
AWS WAF is a web application firewall that helps protect your web applications or APIs from common web services and bots that can affect availability, compromise security, or exploit other features in AWS WAF You can create code rules modifying specific transport patterns
Key Features of AWS WAF
- Customisable rules: Create rules based on IP addresses, HTTP headers, HTTP bodies, or URI strings.
- Rate Limitation: Throttle requests to reduce brute force attacks.
- Integrating AWS Shield: Enhanced DDoS protection.
Setting Up AWS WAF for Your ALB
Step 1: Create a Web ACL
- Navigate to the AWS WAF & Shield console.
- Create a Web ACL:
- Choose Regional Resources for resource type
- Enter a name for your WAF
- Choose the AWS Region.
- Associate it with your ALB.
Step 2: Add Rules to Your Web ACL
Add Custom Rules:
- Originates from a country in: Blocks requests originating from a configured or specified list of countries we will use South Africa and Ireland for testing purposes.
- Rule type-> choose rule builder
- Give your rule a name
- Rule type choose Regular rule
- choose the condition to be evaluated for this rule to apply in our case we will choose matches the statement
- Country Codes here search and select the countries to be locked by this rule.
- Choose IP address
- Then choose what action should be taken should the condition evaluate to true. in our case we want to block the request.
- (Optionally) you may add a custom response
- click next and set Rule Priority
- Configure Metrics — again you can Optionally enable requests sampling if enabled it means you will be able to view requests that matched the rule from from cloud watch ✅
- Finally Review and create your WEB ACL 🙌, takes less than 90 seconds to complete
2. IP Rate-based Rule: Mitigate brute-force attacks by limiting the number of requests from a single IP address. We can add another rule to simulate a DDoS attack from a specific IP and block requests from that IP for a specified rate.
- Rule type-> choose rule builder
- Give your rule a name
- Rule type choose Rate-based rule → Limits request rates for requests that match your criteria. Applies the action to matching requests when the limit is reached, and removes the action when the rate falls below the limit.
- Rate Limit -> 1000
- Evaluation Window -> 5minutes / 300 seconds if a count of requests from an IP exceeds the rate limit, then requests from that IP will be blocked and will reset after 5min.
- Requests aggregation: Source Ip Address.
- Scope of Inspection and rate limiting, we want to consider all requests into our application so choose consider all requests
- Action -> Block
- Custom Response -> Enabled
- Response Code 42
- Message Json Response
{
"error":"You have sent too many requests. Please try again later."
}
Step 3: Test Your Configuration
- Simulate Traffic: Use tools like Apache JMeter or AWS’s built-in testing tools to simulate traffic.
- Monitor WAF Logs: Use Amazon CloudWatch to monitor logs and adjust your rules as necessary.
For testing purposes I will make use of a VPN connection
- Testing with VPN Off
We can also test this using curl:
3. IP Rate-based Rule: To simulate and test if the Rule is working as expected we will make use of a tool called Apache Benchmark this tool allows us to send a distributed amount of request to our application.
It’s crucial to perform these tests responsibly:
- Permission: Ensure you have explicit permission to perform these tests on the target system.
- Environment: Conduct the tests in a controlled, non-production environment to avoid disrupting real users.
- Monitoring: Monitor your system’s performance and be ready to stop the test if it causes issues.
- Install Apache Benchmark
Windows:
> choco install apache-httpd
# source: https://chocolatey.org/packages/apache-httpd
Mac os:
As of macos bigsur ab is installed by default in macos, if not installed use:
brew install httpd
Ubuntu:
> apt-get install apache2-utils
# source: https://bobcares.com/blog/apache-benchmark-install-ubuntu/
Run the Apache Benchmark command on a terminal:
- This command, will send 10000 requests to your application with 100 concurrent requests at at time, simulating a high load scenario.
- You may adjust the “-n” and “-c” values to increase or decrease the load as needed for your testing
ab -n 10000 -c 100 http://your-app-ip/recipes
This is ApacheBench, Version 2.3 <$Revision: 1903618 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking medium-apps.realhandsonlabs.net (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software:
Server Hostname: medium-apps.realhandsonlabs.net
Server Port: 80
Document Path: /recipes
Document Length: 254 bytes
Concurrency Level: 100
Time taken for tests: 56.806 seconds
Complete requests: 10000
Failed requests: 4979
(Connect: 0, Receive: 0, Length: 4979, Exceptions: 0)
Non-2xx responses: 4979
Total transferred: 3474830 bytes
HTML transferred: 1623864 bytes
Requests per second: 176.04 [#/sec] (mean)
Time per request: 568.063 [ms] (mean)
Time per request: 5.681 [ms] (mean, across all concurrent requests)
Transfer rate: 59.74 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 231 314 682.2 243 7274
Processing: 232 247 27.1 245 1030
Waiting: 232 246 27.1 244 1030
Total: 465 560 682.6 488 7528
Percentage of the requests served within a certain time (ms)
50% 488
66% 493
75% 497
80% 499
90% 505
95% 513
98% 538
99% 3490
100% 7528 (longest request)
- From the command results we can see we had 4979 failed requests which means High Failure Rate this indicates that almost half of the requests did not succeed. This confirms we have rate limiting in place(WAF-Blocking)
- At this point if we try to access the ap from the browser we should be getting an error with the message body we set.
Wait 5min minutes and reload you should get a successful request this time.
There are many other rules we can apply such as:
- String Match Rule: Block requests with specific patterns in the URI, headers, or body.
- SQL Injection Match Conditions: Detect and block SQL injection attempts.
- XSS (Cross-Site Scripting) Match Conditions: Detect and block cross-site scripting attacks.
- Rate-Based Rules: Limit the size of requests to prevent attacks like buffer overflow.
- Size Constraint Rules: Limit the size of requests to prevent attacks like buffer overflow.
- Regex Match Rules: regular expressions to match and block requests based on patterns. and many more.
Monitoring and Maintenance
Use CloudWatch for Insights
- Dashboards: Create custom dashboards to monitor the number of blocked requests.
- Alarms: Set up alarms to notify you of unusual traffic patterns.
Regular Updates
- Update Managed Rules: AWS continuously updates managed rules to cover new threats.
- Review Custom Rules: Periodically review and adjust your custom rules based on the latest traffic patterns.
Conclusion
By using an AWS WAF with your ALB, you can significantly increase the resilience of your web application against DDoS attacks. While setting up an AWS WAF requires careful planning and management, the security it provides is well worth the effort. Congratulations we have reached the end 🚀
What’s Next 👀
We had many parts involved here and we surely can make some adjustments to make our lives easier like consider using Terraform to template our infrastructure deployment, CI/CD to easily deploy our apps.
And most importantly we can make changes on the security groups of our instances to only allow connections from the security group, and add ACM certificates on the ALB so we can have a secure HTTPS connection. as in below screenshot.