visit
In this post, I want to detail how to do it with Apache APISIX. Note I take most of the material from the workshop.
The limit-count
plugin is a good candidate for this post.
routes:
- uri: /get
upstream:
nodes:
"//httpbin.org:80": 1
plugins:
limit-count: #1
count: 1 #2
time_window: 60 #2
rejected_code: 429 #3
#END
limit-count
plugin503
curl -v //localhost:9080/get
curl -v //localhost:9080/get
HTTP/1.1 429 Too Many Requests
Date: Tue, 09 Jul 2024 06:55:07 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 241
Connection: keep-alive
X-RateLimit-Limit: 1 #1
X-RateLimit-Remaining: 0 #2
X-RateLimit-Reset: 59 #3
Server: APISIX/3.9.1
<html>
<head><title>429 Too Many Requests</title></head>
<body>
<center><h1>429 Too Many Requests</h1></center>
<hr><center>openresty</center>
<p><em>Powered by <a href="//apisix.apache.org/">APISIX</a>.</em></p></body>
</html>
To configure per-consumer rate limiting, we first need to implement request authentication. APISIX offers many authentication plugins; we shall use the simplest one, . key-auth
checks a specific HTTP request header - apikey
by default.
consumers:
- username: johndoe #1
plugins:
key-auth:
key: john #2
- username: janedoe #1
plugins:
key-auth:
key: jane #2
curl -H 'apikey: john' localhost:9080/get #1
curl -H 'apikey: jane' localhost:9080/get #2
johndoe
janedoe
In general, you attach plugins to APISIX routes but can also attach them to consumers. We can now move the limit-count
plugin.
routes:
- uri: /get
upstream:
nodes:
"httpbin:80": 1
plugins:
key-auth: ~ #1
consumers:
- username: johndoe
plugins:
key-auth:
key: john
limit-count:
count: 1 #2
time_window: 60
rejected_code: 429
- username: janedoe
plugins:
key-auth:
key: jane
limit-count:
count: 5 #2
time_window: 60
rejected_code: 429
#END
key-auth
johndoe
has a lower limit count than janedoe
. Did he forget to pay his subscription fees?
curl -H 'apikey: john' localhost:9080/get
curl -H 'apikey: john' localhost:9080/get
curl -H 'apikey: jane' localhost:9080/get
curl -H 'apikey: jane' localhost:9080/get
We never attach permissions directly to identities in Identity Management systems. It's considered bad practice because when a person moves around the organization, we need to add and remove permissions one by one. The good practice is to attach permissions to groups and set the person in that group. When the person moves, we change their group; the person loses permissions from the old group and gets permissions from the new group. People get their permissions transitively via their groups.
Apache APISIX offers an abstraction called a Consumer Group
for this.
consumer_groups:
- id: 1
plugins:
limit-count:
count: 1
time_window: 60
rejected_code: 429
- id: 2
plugins:
limit-count:
count: 5
time_window: 60
rejected_code: 429
consumers:
- username: johndoe
group_id: 1
plugins:
key-auth:
key: john
- username: janedoe
group_id: 2
plugins:
key-auth:
key: jane
curl -H 'apikey: john' localhost:9080/get
curl -H 'apikey: john' localhost:9080/get
curl -H 'apikey: jane' localhost:9080/get
curl -H 'apikey: jane' localhost:9080/get
consumers:
- username: johndoe
group_id: 2 #1
plugins:
key-auth:
key: john
limit-count:
count: 1 #2
time_window: 60
rejected_code: 429
- username: janedoe
group_id: 2
plugins:
key-auth:
key: jane
johndoe
to group 2
curl -H 'apikey: john' localhost:9080/get
curl -H 'apikey: john' localhost:9080/get #1
johndoe
hits the limit here, but janedoe
now only has four requests left from this minute, as the former used one request
To go further: