Blocking IP on MITIGATOR with Nginx and Fail2ban
The following web server security configuration is described:
- Nginx module
ngx_http_limit_reqdetects the excess of the request limit; - fail2ban analyzes
error.log, which Nginx uses to report on the excesses; - IP is added to the list of blocked by MITIGATOR API.
MITIGATOR API client
There is a script mitigator.py (download)
to manage MITIGATOR, in particular to temporarily block an IP address via
the MITIGATOR API. If necessary, the script can be modified
to perform any other actions on MITIGATOR. The script uses only the
standard modules and works with Python 2.7+ and Python 3.
To run the script, you need the MITIGATOR account and the protection policy ID
(for example, 42 in the URL .../policies/42 when accessing MITIGATOR).
The script also accepts IP and blocking time in seconds.
The description of all parameters is printed with the --help (-h) option.
Nginx setup
The ngx_http_limit_req module is built into Nginx and allows you to limit
the number of requests per second (RPS) via the Nginx configuration.
Request limit refers to zone. Typically, the zone is the client’s IP (eg. requests from it are limited) or the URI on the site (requests to it are limited), but more complex combinations of request parameters are also possible
Zones are described in the http context. Let’s describe a perip (per IP) zone
that can track a 10 RPS limit violation for any one of 10 million IP addresses.
To do this, add the line to /etc/nginx.conf through an intermediate file:
To apply this limit to a part of the site (the location context) and to prevent access
from one IP to the page more than 10 times per second, use the following directive in
/etc/nginx/sites-available/default (if requests are limited for the default site):
Here burst=20 allows bursts of activity up to 20 RPS
(but no more than 10 RPS on average, as described for the zone), and nodelay
means that requests over the limit are dropped, and do not wait in line (relevant for DDoS).
Let’s update Nginx config:
When the limit is exceeded, lines like this appear in error.log:
fail2ban setup
The fail2ban utility analyzes the logs and, if it finds the specified signs, performs blocking actions. Fail2ban also allows you to manage lists of blocked addresses.
Let’s place the blocking script:
Let’s create a new fail2ban action that will call the script:
Labels <server>, <user>, <password>, <policy>, <ip> and <bantime>
must be written as is - these are parameters that will be automatically replaced
with correct values. The --no-verify key is needed if MITIGATOR works with
a self-signed certificate and you need to disable its verification.
Let’s create a restriction (jail) that will block IP based on entries in error.log:
The nginx-limit-req module comes with fail2ban and finds the required lines.
The banaction=... line specifies the actual parameters of the action: server,
username, password, policy ID. For example, the blocking time is 10 minutes.
Let’s reboot fail2ban rules:
Checking work
Traffic must go through MITIGATOR, general protection and protection of the selected policy must be enabled.
You can simulate an attack with the httperf utility:
With a successful setup, a few seconds after running httperf on the server,
you can see that fail2ban has worked:
On MITIGATOR in the TBL policy card you can check that the attacker’s IP (192.0.2.10 in the example) is on the list of temporarily blocked.
You can unblock IP either through MITIGATOR or fail2ban:
If you do not need to block an IP through fail2ban, and it is undesirable to add it to the «White list» (WL or TWL) on MITIGATOR, you can ignore the IP at the fail2ban level:
If fail2ban did not work, errors can be observed in its log: