Hi all!

we are currently exploring the different options available within HAProxy to 
protect our systems from attacks and accidental overloads. We got the basics 
figured out by following the very well written introduction to stick tables 
[1]. What we ended up with is something like this:

  stick-table type ip size 10m expire 10s store http_req_rate(10s)
  tcp-request content track-sc0 src
  http-request deny status 429 content-type "text/plain" string "429: Too Many 
Requests" if { sc_http_req_rate(0) gt 5 }

This allows us to protect the systems behind HAProxy very well by not letting 
request through that are above our defined limit. However, we realised that the 
load on HAProxy per blocked request is very similar to the load per "allowed" 
request. The idea we had was to block earlier if we know that an IP already 
made a lot of requests. This would reduce the load on HAProxy since it doesn't 
have to perform a TLS handshake and inspect the request before blocking it. We 
expected to be able to just add the following line to the config and block any 
new connections:

  tcp-request connection reject if { sc_http_req_rate(0) gt 10 }

The idea being that we "softly" limit IPs that exceed our limits a bit, but we 
have the possibility to completely lock out a certain IP if it continues to 
generate a high number of requests.

However, this does not work at all and we do not understand why. Can you please 
explain to us why this doesn't work and if there is a different way to achieve 
this goal?

Blocking based on the connection rate does work as described in the 
documentation [2], which led us to believe that the client IP is available and 
we should be able to reject the connection based on it.

Thanks in advance!

Best Regards,
Max

[1] https://www.haproxy.com/blog/introduction-to-haproxy-stick-tables/
[2] 
https://cbonte.github.io/haproxy-dconv/2.5/configuration.html#4-tcp-request%20connection

PS: We are aware that open connections could keep sending requests and loading 
HAProxy even if the connection rejection rule kicks in, this could be solved by 
adding a `http-request reject if { sc_http_req_rate(0) gt 10 }` which closes 
the connection.

Reply via email to