Key Authentication and Rate Limiting plugins of Kong on Flask API

In the previous post, we discussed about registering the Flask API to KONG service. In this tutorial, we discussed about applying KONG plugins like Key Authentication and Rate Limiting on the registered API.

  1. Key-Authentication
  2. Rate-limiting

Key-Authentication Plugin

Access control of consumer over the API

This Key Authentication plugin can be added to a service or a route. Consumers can add their Apikey either in a querystring parameter or a header to authenticate their requests. Plugins registered can be viewed at http://localhost:8001/plugins.

Adding key-auth plugin to the service

you should provide service_id(d4079539–45d0–4798–96a8–6ac39d86b6cb) or service_name (testApi) of that specific service to register the key-auth plugin. Get the service details at http://localhost:8001/services. Register the key-auth plugin to the service with the following cQuery.

curl -X POST http://localhost:8001/services/testApi/plugins \
 --data "name=key-auth"

Response:
{“created_at”:1536501460000,”config”:{“key_in_body”:false,”run_on_preflight”:true,”anonymous”:””,”hide_credentials”:false,”key_names”:[“apikey”]},”id”:”0fe22dc7–1bae-4a94–9841-d66469a1faaf”,”enabled”:true,”service_id”:”d4079539–45d0–4798–96a8–6ac39d86b6cb”,”name”:”key-auth”}

The above response clearly tells us to pass “apikey” has to pass as header or querystring parameter.

Now see what happens, if we access our API

curl -i -X GET --url http://localhost:8000/api/v1/test2 --header 'Host: localhost'
Response:
HTTP/1.1 401 Unauthorized
{"message":"No API key found in request"}

Our consumers needs“apikey” to access the service. Lets set apikey to each consumer we registered with the following query.

curl -X POST http://localhost:8001/consumers/consumer1/key-auth --data ""
Response:{"id":"508bee01-613b-4f21-8ced-b098395e0a47","created_at":1536498848000,"key":"M1PyCiEee7QbI44FWC24G4WK7Bb4vZgm","consumer_id":"abd67a95-a247-4141-b329-d74fe6d3fb06"}

Pass the “key” as header or querystring parameter to access the service

curl -i -X GET --url http://localhost:8000/api/v1/test2 --header 'Host: localhost' --header 'apikey: M1PyCiEee7QbI44FWC24G4WK7Bb4vZgm'
HTTP/1.1 200 OK
Response:{“message”:”second end point \”test2\” is called”,”status_code”:200}

Consumer keys can be accessed at http://localhost:8001/consumers/consumer1/key-auth

Adding key-auth plugin to route

delete the key-auth plugin of the service and lets add on the route to test.

curl -i -X DELETE http://localhost:8001/plugins/0fe22dc7-1bae-4a94-9841-d66469a1faaf

set key-auth plugin to the route /api/v1/test1 with the following query.

curl -X POST http://localhost:8001/routes/668ac4ab-4226-45f7-9067-e30c032a840f/plugins --data "name=key-auth"
Response: {"created_at":1536508484000,"config":{"key_in_body":false,"run_on_preflight":true,"anonymous":"","hide_credentials":false,"key_names":["apikey"]},"id":"048d6fcc-f1f0-4f04-b3a4-584754871dd8","enabled":true,"route_id":"668ac4ab-4226-45f7-9067-e30c032a840f","name":"key-auth"}

Key-Auth on route id

Now you can access route /api/v1/test2 without authentication and route /api/v1/test1 with authentication, since we just set the authentication on this route. Lets test this

$ curl -i -X GET --url http://localhost:8000/api/v1/test1 --header 'Host: localhost'
HTTP/1.1 401 Unauthorized
{"message":"No API key found in request"}

The above query passed without apikey and response is 401 Unauthorized

$ curl -i -X GET --url http://localhost:8000/api/v1/test2 --header 'Host: localhost'
HTTP/1.1 200 OK
{"message":"second end point \"test2\" is called","status_code":200}

The above query passed without apikey and the response is 200 OK. Because we added key-auth plugin only on /api/v1/test1 route.

$ curl -i -X GET --url http://localhost:8000/api/v1/test1 --header 'Host: localhost' --header 'apikey: M1PyCiEee7QbI44FWC24G4WK7Bb4vZgm'
HTTP/1.1 200 OK
{"message":"first end point \"test1\" is called","status_code":200}

Here we conclude that we can provide a specific route of the API to specific consumer with key-auth plugin.

Rate Limiting Plugin

This plugin helps us to restrict consumer making requests to our API/Service in a given period of time(seconds, minute, hour, month, year).

This plugin can be enable on a service or route or consumer with consumer_id.

Enabling on Service — restricts every consumer making requests to the service.

Enabling on route — restricts every consumer making requests to the specific route of the service.

Enabling on consumer — restricts only that specified consumer making requests to any routes of the service.

Adding rate-limiting to the service:

$ curl -X POST http://localhost:8001/services/testApi/plugins \
 --data "name=rate-limiting" \
 --data "config.minute=2" \
 --data "config.hour=100"

Response:{“created_at”:1536558895000,”config”:{“minute”:2,”policy”:”cluster”,”redis_timeout”:2000,”hide_client_headers”:false,”hour”:100,”limit_by”:”consumer”,”redis_port”:6379,”redis_database”:0,”fault_tolerant”:true},”id”:”38586082–7619–4bf7-b418-afcc65d37f28",”enabled”:true,”service_id”:”d4079539–45d0–4798–96a8–6ac39d86b6cb”,”name”:”rate-limiting”}

This plugin is by-default limit by consumer. We can send only 2 requests per minute and 100 per hour. Response from Kong after exceeding limit is {“message”:”API rate limit exceeded”}. Lets test this by simple python script.

import requests
from time import sleep
for i in range(1,10):
 response = requests.get(“http://localhost:8000/api/v1/test1?apikey=M1PyCiEee7QbI44FWC24G4WK7Bb4vZgm")
 print(response.ok, response.text)
 sleep(1)

Response of rate-limiting plugin

Similarly you can play around with this rate-limiting plugin on consumer or route of the service too. Specify the consumer_id in the following query to add rate-limiting plugin to the consumer.

$ curl -X POST http://localhost:8001/plugins \
 --data "name=rate-limiting" \
 --data "consumer_id={consumer_id}" \
 --data "config.second=5" \
 --data "config.hour=10000"

To add rate-limiting plugin on the route of the service, you need to add the route_id to the following query.

$ curl -X POST http://localhost:8001/routes/{route_id}/plugins \
 --data "name=rate-limiting" \
 --data "config.minute=2" \
 --data "config.hour=100"

Thanks for reading. Please clap if you like and comment below for any related queries.