Protect TCP/UDP Ports Against DDoS Attacks with CrowdSec and Traefik Proxy
This is a guest post by community member Killian Stein.
Hello everyone — how you’re all doing alright!
I’m back on the CrowdSec Blog and today I'm going to show you how to secure the opening of a TCP/UDP port with Traefik Proxy and CrowdSec.
Last time around, I showed you how to enhance security for your Docker Compose with CrowdSec and Traefik Proxy. If you missed it, go check it out here.
In this tutorial, I’ll show you how to protect your services against DDoS attacks, but there's nothing to stop you from going further with your application's authentication logs.
Before getting technical, let's talk about theory.
Understanding the CrowdSec concepts
To put it simply, the Crowdsec Security Engine analyzes the logs in the acquired configuration files using parsers. Once the various parsers have extracted the information and tagged it, we'll have several types of scenarios at our disposal. Scenarios are actually buckets that group elements by tag (e.g., source IP).
Parsers
Now, I told you there were several parsers because there are several levels of parsing.
Firstly, s00-Raw extracts each raw from the logs and applies a tag according to the type defined in the acquis.yaml configuration. It will perform other operations that you'll see during testing.
Next comes s01, whose role is to parse the log message, applying the GROK pattern to extract the data.
Finally, s02 will provide additional information on the extracted data (e.g., GEOIP).
Scenarios
Scenarios are a little simpler. In the S01-parse step, add a log_type label, which you’ll simply capture in your scenario and associate with it. There will then be several possible configurations, and here I'm going to give you a quick introduction to the leaky bucket, as that's the one I’m going to use for this tutorial.
Once the corresponding log_type and our source IP have been retrieved from the parser, we can configure a scenario to create a bucket for each source IP. This bucket will be able to hold 5 objects and I’ll indicate that it can remove one object every 10 seconds. So, if you follow the 6th object, an alert will be generated indicating the source IP.
Now that we've got the big picture, how can you simplify your life?
Here are two useful links:
- CrowdSec Hub: Make sure what you are trying to do doesn’t already exist, or you can start working on an existing file. I’ll give you an example of this during this tutorial.
- https://playground.crowdsec.net/#/grok:The playground will help you validate your GROK pattern and check that all the data has been extracted.
Let’s go!
The architecture below represents what I’ll help you build in this tutorial.
Here, I’m not going to ban IPs at the Traefik level but rather use Linux's firewall bouncer to apply the decision. Bouncers — or Remediation Components — consume CrowdSec decisions. There are a bunch of different types of Remediation Components, but the Traefik plugin doesn't support CrowdSec middleware for TCP/UDP frames. Find more information in the Traefik documentation.
First, I'll rent a server from OVH (Ubuntu 23.10 - UEFI) and install the Docker Engine.
Next, I'll use Docker Compose for my file and check that I can connect to MongoDB via the port in TCP and TLS. Here, I'm enabling Traefik's debug mode logs, as this is necessary to retrieve TCP/UDP connection logs. (Maybe a feature request to Traefik 🙂)
Docker Compose file:
This is what you’ll see in MongoDB Compass:
The certificate verification is:
Let’s check the UDP port.
And now let’s check Traefik logs.
Perfect!
Creating the parser
You now have the logs you need to run your tests, so let's move on to creating the parser. I grab a few lines and put them in a test.log file, which I’ll use for my tests. Here's my test.log file:
First of all, I'd like to confirm that my GROK pattern extracts the data correctly. To create the pattern, you can use this link to find example patterns or use AI. Find more info on this process here.
Now let’s run to the playground!
As you can see, the data got normalized. As I mentioned, I'm going to the CrowdSec hub to start with a working configuration.
I'll start from LaPresidente's file on the adguard parser. Once the file has been cloned and adapted for my use case, this is what it looks like:
Now let's test the parser.
I'll let you analyze the output of the command for yourself. The -v argument will allow you to see any fields added or removed, as well as the data.
This enormously helps in understanding the path of our log.
Here are the results of the TCP line:
And the UDP line:
Creating the scenario
Let's move on to the scenario. I'll be using LaPresidente’s scenario as a starting point.
Here's the adapted file:
I'll create a file in the scenarios folder and copy/paste the above code.
If you run the test again, you’ll see that it now passes into the scenario.
Now that we've checked that the parsers and scenario are working, we'll add the Traefik logs to the CrowdSec acquired file.
I’m going to generate a bouncer API key on the CrowdSec container, keeping it carefully to one side 😉
Later, I'll retrieve the IP of the CrowdSec container with the following command:
Installing the CrowdSec Firewall bouncer
Time to install the CrowdSec Firewall bouncer to ban the IP that's going to flood. You have a few options, the easiest one is to add CrowdSec source and apt install package.
Note: Later on, to update the bouncer, only apt update is needed.
Install the firewall bouncer with apt install:
You can find more details on this this process in the CrowdSec documentation here and here.
For this tutorial, I'm going to the repository of CrowdSec firewall bouncer to download and install the package manually.
Then simply unzip and run ./install.sh and follow the guide.
The service is failing, that's normal! In the configuration file, enter CrowdSec's IP and API key.
Modify the API_URL
and API_KEY
lines.
Let's put it to the test with a small flood on the server with HPING3:
Ok let's check CrowdSec alerts.
Check with cscli metrics:
If you check the bouncer firewall logs, here’s what you’ll see:
And if you try to scan the port from the banned machine, you won't get a result if the port is open or not because the host is unreachable.
Perfect, isn't it?
Let’s sum up
Now you know which path to take to create your parsers and scenarios. I also hope that this guide has helped you understand the general workflows and will help you protect your production or homelab projects!
If you need this parser/scenario, it is available directly from the CrowdSec Hub and on GitHub.
And if you don’t want to leave your cscli console, you can directly access it with cscli parsers install aidalinfo/tcpudp-flood-traefik and cscli scenarios install aidalinfo/tcpudp-flood-traefik.
Thanks for reading and see you soon!
About Killian Stein
As a young IT enthusiast and teaching enthusiast, Killian tries to demystify modern technologies. He is a DevSecOps Engineer at Aidalinfo, where he is learning and consolidating his experience of the cloud and open source tools. If you liked Killian’s article and are curious to follow his next projects, don't hesitate to connect with him on LinkedIn. New projects are coming soon!