How do I use PDK Datastore functions to retrieve DB entity information in a pre-function plugin?
How to use PDK Datastore functions to retrieve DB entity information in a `pre-function` plugin
How do I use PDK Datastore functions to retrieve DB entity information in a pre-function plugin?
The untrusted_lua sandbox tier for pre-function/post-function/serverless-functions plugins determines whether kong.db is available at all, and a stricter tier can make it entirely absent. A lax-style tier restores kong.db, but only as a curated table exposing a fixed set of core entities (services, routes, consumers, plugins, keys, certificates, upstreams, targets, snis) — entities like jwt_secrets are still not reachable. Set untrusted_lua: on (KONG_UNTRUSTED_LUA=on) to restore the full kong.db module with dynamic access to any entity’s DAO.
From there, call the entity’s DAO select function (for example kong.db.jwt_secrets:select_by_key(key)), use kong.log.inspect() to see the row’s fields, then reference the fields you need directly (for example row["secret"], row["consumer"]["id"]).
Overview
Steps
Background
The basic description of the PDK functions can be found here.
The doc mentions the following entities:
-- Core DAOs
local services = kong.db.services
local routes = kong.db.routes
local consumers = kong.db.consumers
local plugins = kong.db.pluginsHowever there are more rows in the DB that can be referenced.
Important prerequisite: the untrusted_lua sandbox tier for pre-function/post-function/serverless-functions plugins controls whether kong.db is available at all. Under a stricter tier, kong.db may be entirely absent from the sandboxed environment, causing the code below to fail with attempt to index field 'db' (a nil value). A more permissive tier may expose kong.db only as a curated table limited to a fixed set of core entities (services, routes, consumers, plugins, keys, certificates, upstreams, targets, snis) — jwt_secrets, and any other entity outside that fixed list, would still not be reachable. To use kong.db.jwt_secrets (or any other non-core-entity DAO) as shown below, untrusted_lua must be set to on (KONG_UNTRUSTED_LUA=on in kong.conf/env), which restores the full kong.db module with dynamic access to every entity’s DAO. This is a global, node-wide setting — check your Kong Gateway version’s documentation for its exact untrusted_lua tier behavior.
Example: Extract a secret from the jwt_secrets table
This example assumes several components are already in place:
-
Consumer and JWT Credential already exist in Kong.
-
Service / Route / JWT plugin installed
JWT credential details:
Key: test-key
Secret: test-secretThis example will focus a lot on the pre-function plugin code, how to determine the information available and how to use it.
-
Find the functions needed to invoke row retrieval for a specific table:
As this example is using the JWT plugin and the
jwt_secretstable, I went looking inside the jwt plugin code on the public github and found theselect_by_keyfunction could be used to return details of a jwt_secret row for any particular key.Reference code.
The magic line is:
local row, err = kong.db.jwt_secrets:select_by_key(jwt_secret_key)Inside the
pre-functionplugin’s access phase, put the following code so we can test the error handling:local jwt_credential_key = "fake-key" local jwt_secret_row, err = kong.db.jwt_secrets:select_by_key(jwt_credential_key) if jwt_secret_row == nil then kong.log("Error retrieving jwt_secret row") return end kong.log("jwt_secret row retrieved successfully")This will result in the Kong error log showing the error:
[pre-function] Error retrieving jwt_secret rowChanging the code back to use the valid
test-keykey, the success message is logged:[pre-function] jwt_secret row retrieved successfully -
Setup debug function to view all contents of the row:
The Kong PDK has an inspect function for showing the contents of tables.
Update the
pre-functioncode to include and use this function like below:local jwt_credential_key = "test-key" local jwt_secret_row, err = kong.db.jwt_secrets:select_by_key(jwt_credential_key) if jwt_secret_row == nil then kong.log("Error retrieving jwt_secret row") return end kong.log("jwt_secret row retrieved successfully") kong.log.inspect.on() kong.log.inspect(jwt_secret_row) kong.log.inspect.off()Output row details:
| 2023/11/23 03:41:05 [debug] 2395#0: *2646 |{ | 2023/11/23 03:41:05 [debug] 2395#0: *2646 | algorithm = "HS256", | 2023/11/23 03:41:05 [debug] 2395#0: *2646 | consumer = { | 2023/11/23 03:41:05 [debug] 2395#0: *2646 | id = "1e31f55a-90a5-4838-afb9-9664b4f70929" | 2023/11/23 03:41:05 [debug] 2395#0: *2646 | }, | 2023/11/23 03:41:05 [debug] 2395#0: *2646 | created_at = 1700701173, | 2023/11/23 03:41:05 [debug] 2395#0: *2646 | id = "8d50298c-6231-407f-be5f-5942d9bed606", | 2023/11/23 03:41:05 [debug] 2395#0: *2646 | key = "test-key", | 2023/11/23 03:41:05 [debug] 2395#0: *2646 | secret = "test-secret" | 2023/11/23 03:41:05 [debug] 2395#0: *2646 |} -
Use the discovered information to extract and use any values needed:
The final code for this example removes the debug function as we now know the contents of the table, and we can finally structure our code to use the details provided.
Final Code:
local jwt_credential_key = "test-key" local jwt_secret_row, err = kong.db.jwt_secrets:select_by_key(jwt_credential_key) if jwt_secret_row == nil then kong.log("Error retrieving jwt_secret row") return end kong.log(jwt_secret_row["secret"]) kong.log(jwt_secret_row["consumer"]["id"]) kong.log(jwt_secret_row["algorithm"])Kong log output:
[pre-function] test-secret [pre-function] 1e31f55a-90a5-4838-afb9-9664b4f70929 [pre-function] HS256