Ambassador Edge Stack is able to perform Rate Limiting based on JWT Token claims from either a JWT or OAuth2 Filter implementation. This is because Ambassador Edge Stack deliberately calls the
ext_authz filter in Envoy as the first step when processing incoming requests. In Ambassador Edge Stack, the
ext_authz filter is implemented as a Filter resource. This explicitly means that Ambassador Edge Stack Filters are ALWAYS processed prior to RateLimit implementations. As a result, you can use the
injectRequestHeader field in either a JWT Filter or an OAuth Filter and pass that header along to be used for RateLimiting purposes.
- Ambassador Edge Stack
- A working Keycloak instance and Keycloak Filter
- A service exposed with a Mapping and protected by a FilterPolicy
Here is a YAML example that describes the setup:
In order to extract the claim, we need to have the Filter use the
injectRequestHeader config and use a golang template to pull out the exact value of the
name claim in our access token JWT and put it in a Header for our RateLimit to catch. Configuration is similar for both OAuth2 and JWT.
Now that the header is properly added, we need to add a label to the Mapping of the service that we want to rate limit. This will determine if the route established by the Mapping will use a label when Ambassador Edge Stack is processing where to send the request. If so, it will add the labels as metadata to be attached when sent to the
RateLimitService to determine whether or not the request should be rate-limited.
We now have appropriate labels added to the request when we send it to the rate limit service, but how do we know what rate limit to apply and how many requests should we allow before returning an error? This is where the RateLimit comes in. The RateLimit allows us to create specific rules based on the labels associated with a particular request. If a value is not specified, then each unique value of the
x-token-name header that comes in will be associated with its own counter. So, someone with a
name JWT claim of "Julian" will be tracked separately from "Jane".
Now we can navigate to our backend in a browser at
https://host.example.com/backend/. After logging in, if we keep refreshing, we will find that our 11th attempt will respond with a blank page. Success!
We've noticed that the user "Julian" uses bad code that abuses the API and consumes way too much bandwidth with his retries. As such, we want a user with the exact
name claim of "Julian" to only get 2 requests per minute before getting an error.