Technology

Key Authentication and Rate Limiting plugins of Kong on Flask API

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

  1. Key-Authentication
  2. Rate-limiting

Key-Authentication Plugin

Access control of consumer over the API
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 OKResponse:{“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
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-authplugin 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. From the query above, 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
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"