Kong
Kong Gateway does not have a native external auth filter, but the pre-function plugin lets you run arbitrary Lua in the access phase and call Fairvisor Edge’s /v1/decision endpoint.
Plugin configuration (Deck / YAML)
plugins:
- name: pre-function
service: your-api-service # or route: / global
config:
access:
- |
local http = require("resty.http")
-- Build the original URI
local path = kong.request.get_path()
local query = kong.request.get_raw_query()
local uri = query ~= "" and (path .. "?" .. query) or path
-- Call Fairvisor Edge
local client = http.new()
client:set_timeout(200) -- 200 ms
local res, err = client:request_uri(
"http://fairvisor-edge.default.svc.cluster.local:8080/v1/decision",
{
method = "POST",
headers = {
["Authorization"] = kong.request.get_header("authorization"),
["X-Original-URI"] = uri,
["X-Original-Method"] = kong.request.get_method(),
["X-Forwarded-For"] = kong.request.get_header("x-forwarded-for"),
},
}
)
if err then
-- Fail-open: log error and continue
kong.log.err("Fairvisor Edge unreachable: " .. err)
return
end
if res.status == 429 then
-- Propagate rate-limit headers to the caller
local headers = res.headers
kong.response.set_header("Retry-After", headers["Retry-After"])
kong.response.set_header("X-Fairvisor-Reason", headers["X-Fairvisor-Reason"])
kong.response.set_header("RateLimit-Limit", headers["RateLimit-Limit"])
kong.response.set_header("RateLimit-Remaining",headers["RateLimit-Remaining"])
kong.response.set_header("RateLimit-Reset", headers["RateLimit-Reset"])
return kong.response.exit(429, { message = "Rate limit exceeded" })
end
Admin API (JSON)
curl -s -X POST http://localhost:8001/services/your-api/plugins \
-H "Content-Type: application/json" \
--data '{
"name": "pre-function",
"config": {
"access": ["<lua-script-as-string>"]
}
}'
Fail-open vs fail-closed
The example above fails-open (continues if the edge is unreachable). To fail-closed, replace the kong.log.err block with:
if err then
return kong.response.exit(503, { message = "Rate limit service unavailable" })
end
Passing custom descriptors
Any header you set before the Fairvisor call is available as a header:<name> descriptor key in your policy:
-- Set a pre-resolved tenant ID
kong.request.set_header("X-Tenant-ID", some_resolved_value)
Then in your policy:
{
"limit_keys": ["header:x-tenant-id"],
...
}
Performance considerations
The pre-function plugin runs synchronously in the nginx worker. The Fairvisor call uses resty.http which is non-blocking (coroutine-based). Typical latency is under 1 ms for a local call; set the client:set_timeout to 200 ms to allow for outliers without stalling workers.
For high-throughput APIs, enable HTTP keepalive on the resty.http client:
local httpc = require("resty.http").new()
httpc:set_keepalive(60000, 100) -- 60s idle timeout, max 100 connections