Managing incoming web traffic for your applications is essential to ensuring optimal performance, preventing abuse, and maintaining the security of your cloud infrastructure.
To accomplish this, one of the tools HAProxy Enterprise users have at their disposal is rate limiting—the practice of preventing clients from making too many requests and using system resources unfairly.
In this blog post, we show how you can implement rate limiting based on the ID of the Virtual Private Cloud in Amazon Web Services using HAProxy Enterprise.
Understanding AWS Virtual Private Clouds
What is a VPC?
A virtual private cloud (VPC) is a virtual network dedicated to your AWS account. A VPC runs in an isolated environment from other virtual networks in the AWS Cloud and is required when creating Elastic Compute Cloud (EC2) instances.
Resembling much of a traditional network that you would operate in your own data center, a VPC is capable of hosting web applications and APIs. Running your services on a VPC means reaping the benefits of cloud environments—flexibility, scalability, and resource allocation.
In some situations, customers will configure VPC Peering, which involves connecting two different VPCs together to open a network between them. Sometimes one of these VPCs is beyond your control (where the VPCs have duplicate network address spaces). This means that the traditional way of rate limiting based on Source IP will not work. In those cases, you can use the VPC ID (a unique ID used to identify and manage the cloud network within your AWS account) to configure rate limiting in HAProxy Enterprise.
Understanding rate limiting
Challenges
Managing request rates in your AWS Virtual Private Cloud is crucial to address several challenges:
Unrestricted access may lead to users consuming more than their fair share of resources, impacting the overall performance of your applications.
Uncontrolled requests can expose vulnerabilities and compromise system security.
Unmonitored usage can result in unexpected spikes in cloud expenses.
HAProxy rate limiting
HAProxy Enterprise functions as a reverse proxy, offering rate limiting among a suite of other features to manage the rate of requests flowing into your VPC through the load balancer itself. Its flexible deployment and elastic scalability mean it can easily run in AWS while adapting to sudden changes in traffic demands.
HAProxy Enterprise offers rate limiting, allowing you to combine ACLs, stick tables, and maps to implement a rate limiting solution with granular control and dynamic adaptability.
HAProxy Enterprise rate limiting can be used to protect against DDoS and brute force attacks, enforce fair resource access, optimize backend server performance, and control cloud costs.
For users who want to take their rate limiting in large-scale deployments to the next level, consider HAProxy Fusion Control Plane and HAProxy Enterprise for high performance and simplified management in your AWS environments.
HAProxy Enterprise configuration overview
The configuration guide below outlines setting up rate limiting with HAProxy Enterprise for AWS VPC. This is accomplished by extracting the VPC ID from the request to enforce rate limiting.
Any request that exceeds the specified rate limit will be returned an HTTP status 429 - Too Many Requests response. These denied requests are tracked and stored in stick tables for each VPC ID, along with an aggregated stick table for monitoring overall request rates.
Let’s get started.
Step one: define rate limits
First, define the rate limits in rates.map
. This step defines rate limits based on VPC ID and path.
rates.map: | |
<vpce_id>,/path <limit> | |
<vpce_id>,/path <limit> | |
<vpce_id>,/path <limit> |
An example of what this could look like would be:
vpc-01234567890abcdef,/api 30 |
In this case, requests for a URL that begins with /api
that originate from the given VPC will be limited to 30 requests per minute. The begins with part is defined later when we use the map_beg
function. The per minute time range is defined later, when we create stick tables.
Step two: extract VPC ID
In your frontend, configure the load balancer to accept the Proxy Protocol by adding the accept-proxy
argument to the bind
line:
frontend fe_main | |
bind :80 accept-proxy |
Extract the VPC ID from the TCP connection using fc_pp_tlv
and store it in the variable txn.vpce_id
.
http-request set-var(txn.vpce_id) fc_pp_tlv(0xEA),bytes(1) |
The fc_pp_tlv
fetch method reads Type-Length-Value vectors from a Proxy Protocol header at the start of a TCP connection. AWS uses the Proxy Protocol to send a TLV that contains the VPC ID. To read it, call fc_pp_tlv
with the hexadecimal value 0xEA, according to the AWS documentation on the Proxy Protocol. Then use the bytes
converter to extract the TLV value containing the VPC ID.
fc_pp_tlv
is a feature available since HAProxy Enterprise 2.6 and the community version, HAProxy 2.9.
Step three: construct rate limiting keys
Construct keys for rate limiting and request tracking using the extracted VPC ID.
http-request set-var-fmt(txn.vpcratekey) "%[var(txn.vpce_id)],%[path]" | |
http-request set-var-fmt(txn.vpctrackkey) "%[var(txn.vpce_id)],%[path],%[src]" |
The first key, which we're storing in the variable txn.vpcratekey
, concatenates the VPC ID and requested URL path to form a key. Its job is to map back to one of the rate limits in the rates.map
file. The second key, txn.vpctrackkey
, concatenates the VPC ID, requested URL path, and the client's source IP address. Its job is to keep track of each client's request rate for a given URL path and origin VPC.
Step four: find rate limit in the map file
Next, configure HAProxy Enterprise to look up the rate limit for the current request in the rates.map
file using the key. In this example, our rates.map
file is in the /var/lib/dataplaneapi/storage/maps
directory because we're using HAProxy Fusion, and that's where it stores map files. Adjust this line for where you've stored the rates.map
file.
http-request set-var(req.vpcrate_limit) var(txn.vpcratekey),map_beg(/var/lib/dataplaneapi/storage/maps/rates.map,20) |
Step five: configure backends for request rate tracking
Configure the backend with a stick table to track request rates based on the virtual public cloud ID. In our example, we are using HAProxy Fusion Control Plane to automatically do rate limiting aggregation. In our configuration, we will write data to the ratebyvpc
table and read from the ratebyvpc.agg
one. HAProxy Fusion will automatically aggregate the limits from all HAProxy Enterprise instances into the aggregated table.
backend ratebyvpc | |
stick-table type binary size 1073741824 expire 120000 peers "$peers_section_name" store http_req_rate(1m) | |
backend ratebyvpc.agg | |
stick-table type binary size 1073741824 expire 120000 peers "$peers_section_name" store http_req_rate(1m) |
Step six: track current request
Then we’ll begin monitoring each client's request rate by using the key for request tracking, which you'll recall is a combination of the VPC ID, requested URL path, and the client's source IP address. This information will be stored in the ratebyvpc
stick table.
Add to your frontend:
http-request track-sc0 var(txn.vpctrackkey) table ratebyvpc |
Step seven: find current rate
Find the client's current rate for the VPC and path combination from the aggregated data in the ratebyvpc.agg
table.
http-request set-var(req.vpcrequest_rate) var(txn.vpctrackkey),table_http_req_rate(ratebyvpc.agg) |
Step seven: check for rate abuse and deny requests
Use an ACL to check if the difference between rate limit and current rate is less than 0. If it’s less than 0, deny the request with a 429 response.
acl vpc_rate_abuse var(req.vpcrate_limit),sub(req.vpcrequest_rate) lt 0 | |
http-request deny deny_status 429 if vpc_rate_abuse |
Conclusion
By following these steps to implement HAProxy Enterprise’s rate limiting, you can effectively mitigate challenges like resource overconsumption, security vulnerabilities, and unexpected cost spikes in your AWS VPCs.