Protecting Services With Kong Gateway Rate Limiting
The Kong Gateway Rate Limiting plugin is one of our most popular traffic control add-ons. You can configure the plugin with a policy for what constitutes "similar requests" (requests coming from the same IP address, for example), and you can set your limits (limit to 10 requests per minute, for example). This tutorial will walk through how simple it is to enable rate limiting in your Kong Gateway.
Rate Limiting: Protecting Your Server 101
Let's take a step back and go over the concept of rate limiting for those who aren't familiar.
Rate limiting is remarkably effective and ridiculously simple. It's also regularly forgotten. Rate limiting is a defensive measure you can use to prevent your server or application from being paralyzed. By restricting the number of similar requests that can hit your server within a window of time, you ensure your server won't be overwhelmed and debilitated.
You're not only guarding against malicious requests. Yes, you want to shut down a bot that's trying to discover login credentials with a brute force attack. You want to stop scrapers from slurping up your content. You want to safeguard your server from DDOS attacks.
But it's also vital to limit non-malicious requests. Sometimes, it's somebody else's buggy code that hits your API endpoint 10 times a second rather than one time every 10 minutes. Or, perhaps only your premium users get unlimited API requests, while your free-tier users only get a hundred requests an hour.
If you’re interested in rate limiting for Kubernetes services, check out this video:
Mini-Project for Kong Gateway Rate Limiting
In our mini-project for this article, we're going to walk through a basic use case: Kong Gateway with the Rate Limiting plugin protecting a simple API server. Here are our steps:
Create Node.js Express API server with a single "hello world" endpoint.
Install and set up Kong Gateway.
Configure Kong Gateway to sit in front of our API server.
Add and configure the Rate Limiting plugin.
Test our rate limiting policies.
After walking through these steps together, you'll have what you need to tailor the Rate Limiting plugin for your unique business needs.
To get started, we'll create a simple API server with a single endpoint that listens for a GET request and responds with "hello world." At the command line, create a project folder and initialize a Node.js application:
Then, we'll add Express, which is the only package we'll need:
Lastly, let's create a simple server with our "hello world" endpoint. In your project folder, create an index.js file with these contents:
Now, spin up your server:
In your browser, you can visit http://localhost:3000. Here's what you should see:
Let's also use Insomnia, a desktop client for API testing. In Insomnia, we send a GET request to http://localhost:3000.
Our Node.js API server with its single endpoint is up and running. We have our 200 OK response.
Keep that terminal window with the node running. We'll do the rest of our work in a separate terminal window.
Install and Set Up Kong Gateway
Next, we'll install Kong Gateway to sit in front of our API server. These steps will vary depending on your local environment.
Simple usage of the Rate Limiting plugin supports configuring Kong in DB-less mode with a declarative configuration. That means, instead of sending configurations to Kong Gateway one step at a time, with those configurations stored in a database, we can use a single declarative .yml file for specifying our entire Kong configuration.
After installing Kong, we generate a starter .yml file:
We'll come back to that kong.yml file in a moment.
Now, let's tell Kong where to look for that declarative configuration file upon startup. In /etc/kong, there is a kong.conf.default file that we'll need to copy as kong.conf and then edit:
Next, we edit the kong.conf file. You'll likely need root privileges to do this. There are two edits that we need to make:
Configure Kong Gateway With Our Service and Routes
Before we start up Kong, let's edit the declarative configuration file generated in our project folder. It should look like this:
Let's walk through what this configuration does. After setting the syntax version (2.1), we configure a new upstream service for which Kong will serve as an API gateway. Our service, which we name my-api-server, listens for requests at the URL http://localhost:3000.
We associate a route (arbitrarily named api-routes) for our service with the path /api. Kong Gateway will listen for requests to /api, and then route those requests to our API server at http://localhost:3000.
With our declarative configuration file in place, we start Kong:
Now, in Insomnia, we send a GET request through Kong Gateway, which listens at http://localhost:8000, to the /api path:
Note that, by sending our request to port 8000, we are going through Kong Gateway to get to our API server.
Add the Kong Gateway Rate Limiting Plugin
Now that we have Kong Gateway sitting in front of our API server, we'll add in the Rate Limiting Plugin and test it out. We will need to add a few lines to our kong.yml declarative configuration file:
We've added the entire plugins section underneath our my-api-server service. We specify the name of the plugin, rate-limiting. This name is not arbitrary but refers to the actual rate-limiting plugin in the Kong package.
In this first run, we've configured the plugin with minute: 5, which allows for up to five requests per minute. We've also added hour : 12, which limits the requests per hour to 12. We're using the local policy, which has to do with how Kong will store and increment request counts. We'll talk about this policy configuration more below.
Let's restart Kong:
Now, back in Insomnia, we test out sending some requests to our API endpoint. If you send a request every few seconds, you'll see that the first five requests received a 200 OK response. However, if you exceed five requests within a minute:
The Rate Limiting plugin detects that requests have exceeded the five-per-minute rule. It doesn't let the subsequent request through to the API server. Instead, we get a 429 Too Many Requests response.
Our plugin works!
If you wait a minute and then try your requests again, you'll see that you can get another five successful requests until Kong blocks you again with another 429.
At this point, we've sent 10 requests over several minutes. But you'll recall that we configured our plugin with hour: 12. That means our 11th and 12th requests will be successful. However, the system will reject our 13th request even though we haven't exceeded the five-per-minute rule . That's because we'll have exceeded the 12-per-hour rule.
The Rate Limiting plugin allows you to limit the number of requests per second, minute, hour, day, month and year.
Rate Limiting "Similar" Requests
We've configured Kong to count (and limit) requests to our server in our simple use case so far. More likely, we'll want to apply our rate limits to similar requests. By "similar," we might mean "coming from the same IP address" or "using the same API key."
For example, let's say that all users of our API server need to send requests with a unique API key set in headers as x-api-key. We can configure Kong to apply its rate limits on a per-API-key basis as follows:
The Rate Limiting plugin will apply its limits by grouping requests according to a value found in the x-api-key in the header. Requests with the same x-api-key will be considered "similar" requests.
Let's restart Kong and see this in action:
Back in Insomnia, we'll adjust our GET request slightly by adding a new x-api-key header value. Let's first set the value to user1. We send the request multiple times. Our first five requests return a 200 OK:
When we exceed the five-per-minute rule, however, this is what we see:
If we change the x-api-key to a different value (for example, user2), we immediately get 200 OK responses:
Requests from user2 are counted separately from requests from user1. Each unique x-api-key value gets (according to our rate limiting rules) up to five requests per minute and up to 12 requests per hour.
You can configure the plugin to limit_by IP address, a header value, request path or even credentials (like OAuth2 or JWT).
Counter Storage "Policy"
In our example above, we set the policy of the Rate Limiting plugin to local. This policy configuration controls how Kong will store request counters to apply its rate limits. The local policy stores in-memory counters. It's the simplest strategy to implement (there's nothing else you need to do!).
However, request counters with this strategy are only mostly accurate. If you want basic protection for your server, and it's acceptable if you miscount a request here and there, then the local policy is sufficient.
The documentation for the Rate Limiting plugin instructs those with needs where "every transaction counts" to use the cluster (writes to the database) or redis (writes to Redis key-value store) policy instead.
Advanced Rate Limiting
For many common business cases, the open source Rate Limiting plugin has enough configuration options to meet your needs. For those with more complex needs (multiple limits or time windows, integration with Redis Sentinel), Kong also offers their Rate Limiting Advanced plugin for Kong Konnect.
Let's briefly recap what we did in our mini-project. We spun up a simple API server. Then, we installed and configured Kong Gateway to sit in front of our API server. Next, we added the Rate Limiting plugin to count and limit requests to our server, showing how Kong blocks requests once we exceed certain limits within a window of time.
Lastly, we demonstrated how to group (and count) requests as "similar" with the example of a header value. Doing so enabled our plugin to differentiate counts for requests coming from two different users so that you can apply that rate limit to each user separately.
That's all there is to it. Kong's Rate Limiting plugin makes protecting your server ridiculously simple. As a basic traffic control defense measure, rate limiting can bring incredible power and peace of mind. You can find more details in the rate limiting plugin doc.