In this post, we will go through several methods of securing an HAProxy setup as we talked previous on how to secure nginx. We will discuss Access Control Lists (ACLs), rate limiting, and GeoIP blocking. We will also look at only allowing traffic from specific networks such as Cloudflare.
1. Access Control Lists (ACLs)
HAProxy uses ACLs to test some condition and perform an action based on the test result. Here’s an example of allowing a specific IP address:
frontend http_front
bind *:80
acl allowed_ip src 192.168.1.100
http-request allow if allowed_ip
http-request deny if !allowed_ip
In the example above, HAProxy allows requests only from the IP address 192.168.1.100 and denies the rest.
2. Rate Limiting
Rate limiting can be achieved in HAProxy using the stick-tables. Here is an example:
frontend http_front
bind *:80
stick-table type ip size 200k expire 10s store http_req_rate(10s)
http-request track-sc0 src
acl rate_too_high sc_http_req_rate(0) gt 10
http-request deny deny_status 429 if rate_too_high
This tracks HTTP requests from each source over ten seconds and returns 429 Too Many Requests above the threshold. The older tcp-request connection example tracked connection state rather than the HTTP request counter it later queried. HAProxy stick-table tutorial
3. Allow only Cloudflare IPs
To only allow traffic from Cloudflare, create ACLs for Cloudflare’s IP ranges:
frontend http_front
bind *:80
acl from_cloudflare src -f /etc/haproxy/cloudflare_ips.lst
http-request deny unless from_cloudflare
http-request set-src req.hdr_ip(CF-Connecting-IP) if from_cloudflare
/etc/haproxy/cloudflare_ips.lst contains Cloudflare’s published ranges, one per line. I validate the immediate TCP peer before trusting CF-Connecting-IP; otherwise a direct client could forge the header. I refresh the list from Cloudflare’s official IP ranges.
HAProxy and Fail2Ban
Fail2Ban can be used to monitor HAProxy logs for suspicious activity. The filter below assumes HAProxy’s standard HTTP log format:
defaults
option httplog
Install Fail2Ban, if it’s not already installed.
Create a new filter for HAProxy. Create a new file at
/etc/fail2ban/filter.d/haproxy-http-auth.confwith the following content:[Definition] failregex = ^.*haproxy\[\d+\]: <HOST>:\d+ \[[^]]+\] \S+ \S+/\S+ \S+ 401 \S+ .* "[A-Z]+ [^"]+ HTTP/\d(?:\.\d)?"$Create a new jail in the
/etc/fail2ban/jail.localfile:[haproxy-http-auth] enabled = true filter = haproxy-http-auth logpath = /var/log/haproxy.log maxretry = 3 bantime = 3600 port = http,httpsRestart Fail2Ban to apply the new configuration.
I test the filter against real lines from the same option httplog output before enabling the jail:
sudo fail2ban-regex /var/log/haproxy.log /etc/fail2ban/filter.d/haproxy-http-auth.conf
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
Fail2Ban should now monitor your HAProxy logs and block IPs that repeatedly fail authentication.
Adjusting Timeouts
Timeouts prevent slow or stalled connections from living forever, but these numbers are workload examples rather than universal security values. A file upload, streaming response, or slow upstream may need much longer limits.
There are several directives related to timeout settings:
timeout client 5s
timeout http-request 5s
timeout http-keep-alive 5s
timeout server 5s
timeout client: Similar toclient_header_timeoutin NGINX, it sets the maximum inactivity time on the client side.timeout http-request: Maximum allowed time to wait for a complete HTTP request.timeout http-keep-alive: Maximum allowed time to wait for a new HTTP request to appear.timeout server: Similar tosend_timeoutin NGINX, it sets the maximum inactivity time on the server side.
Buy Me a Coffee