Protect your applications with AWS WAF and CrowdSec
Learn how to configure the AWS WAF bouncer to protect an application running behind an ALB with the ability to block both IPs and countries.
In this article, we will see how to install and configure the newly released AWS WAF bouncer and use it to protect a simple Nginx web server running behind an Application Load Balancer.
Our target infrastructure is:
AWS WAF is a managed Web Application Firewall offering, allowing you to inspect requests and block them (or display a captcha) based on criteria of your choosing.
It can inspect requests to:
- API Gateway REST API
- Cloudfront distributions
- Application Load Balancer
- AppSync GraphQL API
The CrowdSec bouncer takes advantage of this to:
- Either block or display a captcha to IPs or ranges for which CrowdSec has a decision
- Either block or display a captcha to countries for which CrowdSec has a decision
CrowdSec for Windows will also be able to detect network scans that attempt to get past the Windows firewall.
First, we will install CrowdSec and the bouncer.
Add the CrowdSec repository to your system (for this article, we will be using an Ubuntu 20.04 server):
If you are using another OS, please refer to the documentation to install CrowdSec on your distribution: https://docs.crowdsec.net/docs/getting_started/install_crowdsec
Next, we will install CrowdSec:
This command will install CrowdSec and automatically detect supported services running (we already have an Nginx server installed, so CrowdSec will automatically monitor its logs and enable the Nginx collection).
Finally, we will install the bouncer:
This will install the bouncer, and automatically register it with the local API.
You can check that the bouncer registered itself properly by running “cscli bouncers list”.
AWS WAF configuration
In order to be able to use the bouncer, you will need to have created a web ACL (web access control list) in AWS WAF and associate it with a (or multiple) AWS resources.
In this article, we will associate our ACL with an application load balancer (ALB) proxying traffic to an EC2 instance running a simple Nginx server.
We just need to create a new rule using the AWS console, and associate it with our ALB:
As we are adding the ACL to a regional resource (in this case, an ALB), the web ACL must live in the same region.
First, we need to grant the bouncer the permissions to interact with the AWS WAF APIs.
For this article, the bouncer is running on an EC2 instance, so we can create an instance role with the following permissions and associate it to the instance:
Of course, in a real-world deployment, you will want to restrict the permission of the bouncer to the ACLs and rule groups it will manage.
If you are not running the bouncer on EC2 (or do not want to use instance roles), the bouncer also supports authentication with an access key (it will look in $HOME/.aws/ for the default profile or the profile configured in the bouncer).
Before being able to start the bouncer, we will need to configure it with the name of the ACL we created previously, and a few other parameters:
Some explanations on the waf_config section:
- web_acl_name: this is the name of our web ACL, in which the bouncer will add its rule group
- Fallback_action: If the bouncer receives a decision with an unknown type, use that instead
- Rule_group_name: the name of the rule group in which the bouncer will add its rules
- Scope: whether we are creating rules for a CloudFront distribution or not
- Region: the AWS region in which everything will be created
When you’re done editing the configuration, just restart the bouncer by running systemctl restart crowdsec-aws-waf-bouncer for it to create a new rule group in your web ACL and the required IP sets.
It may take a minute for the bouncer to be fully up and running.
We will also modify the CrowdSec profiles.yaml to apply a captcha for all HTTP-related scenarios instead of a classic IP ban.
The profiles.yaml file tells CrowdSec what to do when it receives an alert (i.e., a scenario has been matched enough time for its bucket to overflow).
We will add the following at the top of /etc/crowdsec/profiles.yaml:
This instructs CrowdSec to create a `captcha` decision valid for 4h if the name of the scenario that triggered the alert starts with crowdsecurity/http-.
Restart (or reload) CrowdSec for the changes to take effect.
Testing the bouncer
To do so, we will simply run Nikto, a very noisy web scanner, in order to trigger decisions:
CrowdSec will detect the attack and create a decision:
The bouncer will the get the decision at its next poll cycle (by default, every 10s), and update the WAF configuration to display a captcha to the user (note that AWS may take some time to propagate the new configuration, but in our experience, it takes about 30s in most cases):
If we solve the captcha, we will gain access to the website:
The bouncer also supports decisions at a country level.
First, let’s delete our current decision:
Next, let’s add a ban decision that will apply to all French IPs:
If we visit our website from a French IP, we will get a 403:
In this article, we configured the AWS WAF bouncer to protect an application running behind an ALB and demonstrated its ability to block both IPs and countries. You can also use this bouncer to protect any application running behind CloudFront, a REST API Gateway, or an AppSync GraphQL API.
We have shown the bouncer running on an EC2 instance, but you can also easily run it in a container, for example with AWS Fargate.
The repository for the bouncer is available here: https://github.com/crowdsecurity/cs-aws-waf-bouncer
The documentation is available here: https://docs.crowdsec.net/docs/next/bouncers/aws_waf
The next article on AWS WAF protection will be dedicated to protecting applications in a serverless environment. Stay tuned!