By on July 6, 2020

Custom Authentication and Authorization Framework with Kong

The Problem

Kong Enterprise provides many out-of-the-box plugins to support various access control solutions like basic authentication, key authentication, JWT, LDAP, OAuth 2.0, OpenID Connect, among others. Most of the time, you should be able to find a plugin to suit your needs to protect your private or public APIs using Kong Enterprise without the need of writing your own plugins. However, there could be situations where you have non-standard or custom security requirements to your environment and business.  

Let’s assume a customer has built an in-house authentication and authorization service which has been used extensively by other applications. It’s able to issue and validate a JWT token, perform fine-grained access control based on user rights and determine if the authenticated user has proper permissions to access API and data. The service has exposed APIs for integration purposes. Rather than build custom code in each microservice to integrate with the custom security service, let’s leverage Kong to centralize the integration and allow each microservice to focus on the business logic.  

Use Case: Integrate with Custom Authentication and Authorization Framework

To integrate Kong with the custom identity provider to secure and govern API access, we can develop a custom Kong plugin. This is a sound approach, which will not only simplify your microservices but also help to transition to an OpenID compliant provider down the line by abstracting the application clients from the security service using Kong.  

Solution Overview

The diagram below shows a high-level overview of the solution. The custom authentication service exposes API endpoints to validate the JWT token, check user permissions, etc. The Kong custom plugin will first invoke the authentication service API to validate the JWT token from the request header. If the token is valid, the plugin will do a second check to see if the authenticated user has necessary permissions to access the upstream API and related data.

In this example, the custom authentication service has exposed the following API endpoints for integration:

  • Introspect token: https://<server address>/auth/validate/token
    Check if the token (passed in Authorization header as Bearer token) is valid.
  • Check permission: http://<server address>/auth/validate/customer
    check if the authenticated user has permission to access the customer details based on “custId” in the request JSON body

Custom Plugin Development

One of Kong’s biggest benefits is the ability to extend the platform. Any custom logic can be added during the lifecycle of a request or response as it is proxied through Kong. For this scenario, let’s implement a custom plugin named “custom-auth.” If you’re new to Kong custom plugins, they are fairly straightforward to implement. A plugin requires minimally two files: schema.lua and handler.lua. You may optionally implement business logic in other Lua files, which can be loaded by handler.lua to make your code more modular and manageable. For the “custom-auth” plugin, let’s create the following structure. Please note that we added a third file here, access.lua,  which contains the actual business logic for the custom plugin.

    • schema.lua: Your plugin probably has to retain some configuration entered by the user. This module holds the schema of that configuration and defines rules on it so that the user can only enter valid configuration values.
    • handler.lua: This is the core of your plugin. It is an interface to implement, in which each function will be run at the desired moment in the lifecycle of a request/connection.

 

  • access.lua: This file contains the actual business logic. It will be invoked by handler.lua.

 

Below are further code details and explanations for each.

Schema.lua:

In this case, we have defined three parameters to configure, including token introspection endpoint, permission checking endpoint and header name from where to get the JWT token. All three parameters are mandatory in this case (required = true). We have also added the logic to validate if the endpoints are entered in proper URL format.

handler.lua:

In this case, this file is rather simple and will invoke a function from another file “access.lua,” as highlighted in line 2. This way, you can make your business logic more modular when writing more complex plugins.

access.lua:

This file contains the actual logic to perform token introspection and permission check by interacting with the custom authentication service. The main function that will be executed first is run(conf), as shown in the handler.lua code above. It will check if there is an Authorization token in the HTTP request header. If not, it will return an error; otherwise, it will continue to invoke the next function, introspect_access_token(access_token, customer_id), where the authentication and authorization endpoints of the custom auth service will be executed in sequence to determine if the user has valid access token and correct access permission to view the customer’s details.

Configuration and Testing

Let’s now try to deploy the custom plugin to Kong Enterprise and test it. First, we will create a folder named “custom-auth” under the directory /usr/local/share/lua/5.1/kong/plugins. You can find other out-of-the-box plugins here, which serve as good reference implementations. Sometimes you may find it convenient to replicate one of the plugins and modify its behavior when necessary. The directory structure looks like the following:

Next, we will configure Kong Enterprise to load this plugin by setting the following property in /etc/kong/kong.conf file and then restart the Kong instance.

If you are running Kong Enterprise in a container environment, you can package the plugin and rebuild the docker image, and then configure the plugins setting via KONG_PLUGINS environment variable.

Now, you should be able to find the custom plugin at the bottom of the plugins page. You can enable this plugin on the service or route that you are trying to protect from unauthorized access.

Below are sample test results to verify this plugin is working properly.

  1. Query returns 200 status code if a valid token is provided in the header and the user access. 

2. Query returns 401 unauthorized error if the token is not valid, which means the authentication check failed.

3. The query returns 401 unauthorized error if the user doesn’t have access.

Conclusion

Kong’s platform can be easily extended and integrated with custom, external systems by implementing custom plugins. This allows Kong to easily integrate with any existing systems to address current requirements as well as address future custom requirements that may arise.  This benefit is one of the main reasons customers choose Kong. In this write up, we covered how Kong Enterprise can be integrated with a third-party access control system, but it’s quite straightforward to integrate with any external system or have Kong perform any logic as part of the request/response lifecycle. I hope you have enjoyed reading this blog post. If you have any interesting ideas and use cases, we welcome your feedback.