Plugin Development - Implementing Custom Logic

Note: This chapter assumes that you are familiar with Lua.

A Kong Gateway (OSS) plugin allows you to inject custom logic (in Lua) at several entry-points in the life-cycle of a request/response or a tcp stream connection as it is proxied by Kong Gateway (OSS). To do so, the file kong.plugins.<plugin_name>.handler must return a table with one or more functions with predetermined names. Those functions will be invoked by Kong Gateway (OSS) at different phases when it processes traffic.

The first parameter they take is always self. All functions except init_worker can receive a second parameter which is a table with the plugin configuration.

Module

  1. kong.plugins.<plugin_name>.handler

Available contexts

If you define any of the following functions in your handler.lua file you’ll implement custom logic at various entry-points of Kong Gateway (OSS)’s execution life-cycle:

  • HTTP Module is used for plugins written for HTTP/HTTPS requests
Function namePhaseDescription
init_workerinit_workerExecuted upon every Nginx worker process’s startup.
certificatessl_certificateExecuted during the SSL certificate serving phase of the SSL handshake.
rewriterewriteExecuted for every request upon its reception from a client as a rewrite phase handler.
In this phase, neither the Service nor the Consumer have been identified, hence this handler will only be executed if the plugin was configured as a global plugin.
accessaccessExecuted for every request from a client and before it is being proxied to the upstream service.
responseaccessReplaces both header_filter() and body_filter(). Executed after the whole response has been received from the upstream service, but before sending any part of it to the client.
header_filterheader_filterExecuted when all response headers bytes have been received from the upstream service.
body_filterbody_filterExecuted for each chunk of the response body received from the upstream service. Since the response is streamed back to the client, it can exceed the buffer size and be streamed chunk by chunk. This function can be called multiple times if the response is large. See the lua-nginx-module documentation for more details.
loglogExecuted when the last response byte has been sent to the client.

Note: If a module implements the response function, Kong Gateway (OSS) will automatically activate the “buffered proxy” mode, as if the kong.service.request.enable_buffering() function had been called. Because of a current Nginx limitation, this doesn’t work for HTTP/2 or gRPC upstreams.

To reduce unexpected behaviour changes, Kong Gateway (OSS) does not start if a plugin implements both response and either header_filter or body_filter.

  • Stream Module is used for Plugins written for TCP and UDP stream connections
Function namePhaseDescription
init_workerinit_workerExecuted upon every Nginx worker process’s startup.
prereadprereadExecuted once for every connection.
loglogExecuted once for each connection after it has been closed.
certificatessl_certificateExecuted during the SSL certificate serving phase of the SSL handshake.

All of those functions, except init_worker, take one parameter which is given by Kong Gateway (OSS) upon its invocation: the configuration of your plugin. This parameter is a Lua table, and contains values defined by your users, according to your plugin’s schema (described in the schema.lua module). More on plugins schemas in the next chapter.

Note that UDP streams don’t have real connections. Kong Gateway (OSS) will consider all packets with the same origin and destination host and port as a single connection. After a configurable time without any packet, the connection is considered closed and the log function is executed.

handler.lua specifications

Kong Gateway (OSS) processes requests in phases. A plugin is a piece of code that gets activated by Kong Gateway (OSS) as each phase is executed while the request gets proxied.

Phases are limited in what they can do. For example, the init_worker phase does not have access to the config parameter because that information isn’t available when kong is initializing each worker.

A plugin’s handler.lua must return a table containing the functions it must execute on each phase.

Kong Gateway (OSS) can process HTTP and stream traffic. Some phases are executed only when processing HTTP traffic, others when processing stream, and some (like init_worker and log) are invoked by both kinds of traffic.

In addition to functions, a plugin must define two fields:

  • VERSION is an informative field, not used by Kong Gateway (OSS) directly. It usually matches the version defined in a plugin’s Rockspec version, when it exists.
  • PRIORITY is used to sort plugins before executing each of their phases. Plugins with a higher priority are executed first. See the plugin execution order below for more info about this field.

The following example handler.lua file defines custom functions for all the possible phases, in both http and stream traffic. It has no functionality besides writing a message to the log every time a phase is invoked. Note that a plugin doesn’t need to provide functions for all phases.

  1. local CustomHandler = {
  2. VERSION = "1.0.0",
  3. PRIORITY = 10,
  4. }
  5. function CustomHandler:init_worker()
  6. -- Implement logic for the init_worker phase here (http/stream)
  7. kong.log("init_worker")
  8. end
  9. function CustomHandler:preread(config)
  10. -- Implement logic for the preread phase here (stream)
  11. kong.log("preread")
  12. end
  13. function CustomHandler:certificate(config)
  14. -- Implement logic for the certificate phase here (http/stream)
  15. kong.log("certificate")
  16. end
  17. function CustomHandler:rewrite(config)
  18. -- Implement logic for the rewrite phase here (http)
  19. kong.log("rewrite")
  20. end
  21. function CustomHandler:access(config)
  22. -- Implement logic for the rewrite phase here (http)
  23. kong.log("access")
  24. end
  25. function CustomHandler:header_filter(config)
  26. -- Implement logic for the header_filter phase here (http)
  27. kong.log("header_filter")
  28. end
  29. function CustomHandler:body_filter(config)
  30. -- Implement logic for the body_filter phase here (http)
  31. kong.log("body_filter")
  32. end
  33. function CustomHandler:log(config)
  34. -- Implement logic for the log phase here (http/stream)
  35. kong.log("log")
  36. end
  37. -- return the created table, so that Kong can execute it
  38. return CustomHandler

Note that in the example above we are using Lua’s : shorthand syntax for functions taking self as a first parameter. An equivalent unshortened version of the access function would be:

  1. function CustomHandler.access(self, config)
  2. -- Implement logic for the rewrite phase here (http)
  3. kong.log("access")
  4. end

Migrating from BasePlugin module

The BasePlugin module is deprecated and will be removed in a future version of Kong Gateway (OSS). If you have an old plugin that uses it, replace the initial part:

  1. -- DEPRECATED --
  2. local BasePlugin = require "kong.plugins.base_plugin"
  3. local CustomHandler = BasePlugin:extend()
  4. CustomHandler.VERSION = "1.0.0"
  5. CustomHandler.PRIORITY = 10

with the current equivalent:

  1. local CustomHandler = {
  2. VERSION = "1.0.0",
  3. PRIORITY = 10,
  4. }

You don’t need to add a :new() method or call any of the CustomHandler.super.XXX:(self) methods.

The plugin’s logic doesn’t need to be all defined inside the handler.lua file. It can be be split into several Lua files (also called modules). The handler.lua module can use require to include other modules in your plugin.

For example, the following plugin splits the functionality into three files. access.lua and body_filter.lua return functions. They are in the same folder as handler.lua, which requires and uses them to build the plugin:

  1. -- handler.lua
  2. local access = require "kong.plugins.my-custom-plugin.access"
  3. local body_filter = require "kong.plugins.my-custom-plugin.body_filter"
  4. local CustomHandler = {
  5. VERSION = "1.0.0",
  6. PRIORITY = 10
  7. }
  8. CustomHandler.access = access
  9. CustomHandler.body_filter = body_filter
  10. return CustomHandler
  1. -- access.lua
  2. return function(self, config)
  3. kong.log("access phase")
  4. end
  1. -- body_filter.lua
  2. return function(self, config)
  3. kong.log("body_filter phase")
  4. end

See the source code of the Key-Auth Plugin for an example of a real-life handler code.

Plugin Development Kit

Logic implemented in those phases will most likely have to interact with the request/response objects or core components (e.g. access the cache, and database). Kong Gateway (OSS) provides a Plugin Development Kit (or “PDK”) for such purposes: a set of Lua functions and variables that can be used by Plugins to execute various gateway operations in a way that is guaranteed to be forward-compatible with future releases of Kong Gateway (OSS).

When you are trying to implement some logic that needs to interact with Kong Gateway (OSS) (e.g. retrieving request headers, producing a response from a plugin, logging some error or debug information), you should consult the Plugin Development Kit Reference.

Plugins execution order

Some plugins might depend on the execution of others to perform some operations. For example, plugins relying on the identity of the consumer have to run after authentication plugins. Considering this, Kong Gateway (OSS) defines priorities between plugins execution to ensure that order is respected.

Your plugin’s priority can be configured via a property accepting a number in the returned handler table:

  1. CustomHandler.PRIORITY = 10

The higher the priority, the sooner your plugin’s phases will be executed in regard to other plugins’ phases (such as :access(), :log(), etc.).

Open-source or Free mode

Enterprise

The following list includes all plugins bundled with open-source Kong Gateway or Kong Gateway running in Free mode.

Note: The correlation-id plugin’s execution order is different depending on whether you’re running Kong Gateway in Free mode or using the open-source package.

The current order of execution for the bundled plugins is:

PluginPriority
pre-function+inf
correlation-id100001
zipkin100000
bot-detection2500
cors2000
session1900
jwt1005
oauth21004
key-auth1003
ldap-auth1002
basic-auth1001
hmac-auth1000
grpc-gateway998
ip-restriction990
request-size-limiting951
acl950
rate-limiting901
response-ratelimiting900
request-transformer801
response-transformer800
aws-lambda750
azure-functions749
prometheus13
http-log12
statsd11
datadog10
file-log9
udp-log8
tcp-log7
loggly6
syslog4
grpc-web3
request-termination2
correlation-id1
post-function-1000

The following list includes all plugins bundled with a Kong Gateway Enterprise subscription.

The current order of execution for the bundled plugins is:

PluginPriority
pre-function+inf
correlation-id100001
zipkin100000
exit-transformer9999
bot-detection2500
cors2000
route-by-header2000
session1900
oauth2-introspection1700
acme1007
mtls-auth1006
jwt1005
degraphql1005
oauth21004
vault-auth1003
key-auth1003
key-auth-enc1003
ldap-auth1002
ldap-auth-advanced1002
basic-auth1001
openid-connect1000
hmac-auth1000
request-validator999
jwt-signer999
grpc-gateway998
application-registration995
ip-restriction990
request-size-limiting951
acl950
opa920
rate-limiting-advanced902
graphql-rate-limiting-advanced902
rate-limiting901
response-ratelimiting900
jq811
request-transformer-advanced802
request-transformer801
response-transformer-advanced800
route-transformer-advanced800
response-transformer800
kafka-upstream751
aws-lambda750
azure-functions749
graphql-proxy-cache-advanced100
proxy-cache-advanced100
proxy-cache100
forward-proxy50
prometheus13
canary13
http-log12
statsd11
statsd-advanced11
datadog10
file-log9
udp-log8
tcp-log7
loggly6
kafka-log5
syslog4
grpc-web3
request-termination2
mocking-1
post-function-1000

Next: Plugin configuration ›