Overview
Karna is a WAF (Web Application Firewall) engine that runs as a native Kong Gateway plugin. It loads the OWASP CoreRuleSet at worker start, evaluates incoming requests against those rules plus any rules you write, and either logs or blocks attacks. It needs no other plugin to work.
There are three things you will typically do, each documented here:
- Install and deploy Karna in front of your application (this page).
- Configure the plugin for your service: blocking mode, paranoia level, request limits, audit logging, and more. See Configuration options.
- Write rules: custom detection, sanitization, rate limiting, and CRS exceptions. See Writing rules.
Configuration options
Every setting in the plugin schema, with type, default, and what it does.
Read the config reference →Writing rules
Rule format, variables, operators, transformations, actions, and worked examples.
Read the rule reference →For AI agents
Install the Karna skill into your coding agent so it can deploy, configure, and write rules for you.
Install the skill →Installation
Two supported paths. Use the Docker image for a self-contained stack, or install the plugin into a Kong you already run.
Docker (production)
The production Dockerfile builds one self-contained image: Kong, the OWASP CoreRuleSet, libinjection, the native RE2 / Aho-Corasick scanners, and Karna. Kong runs DB-less; the declarative config in docker/kong.yml puts Karna in front of your backend. Redis is optional — it backs rate limiting, Redis inspection rules, and the auto-ban write actions.
# 1. get the source (the production Dockerfile ships with it) git clone https://github.com/sicuranext/karna.git cd karna # 2. point the upstream at your app: # edit docker/kong.yml -> services[0].url: http://your-app:8080 # 3. build and run (Kong DB-less + Redis) docker compose -f docker/docker-compose.prod.yml up -d --build # traffic now flows: client -> :8000 (Karna / Kong) -> your app
Ports 8000 (proxy) and 8443 (proxy TLS) are exposed. The image bakes in KONG_PLUGINS=bundled,karna and the PCRE backtracking cap KONG_NGINX_HTTP_LUA_REGEX_MATCH_LIMIT=100000, so there is nothing to compile by hand.
Install into an existing Kong
If you already run Kong, install the plugin and its native dependencies, then enable it. Karna needs lua-zlib (gzip bodies), libinjection.so (SQLi/XSS), the OWASP CoreRuleSet on disk, and optionally the native scanners (they fall back to pure Lua if absent).
# lua-zlib must come from the direct rockspec URL — the full # luarocks.org manifest is too large for LuaJIT to parse. luarocks install https://luarocks.org/manifests/brimworks/lua-zlib-1.2-2.rockspec # the plugin itself (from the cloned repo) cd /path/to/karna && luarocks make # libinjection.so git clone --branch v3.10.0 https://github.com/client9/libinjection.git cd libinjection/src && gcc -shared -fPIC -O2 -o /usr/local/lib/libinjection.so \ libinjection_sqli.c libinjection_xss.c libinjection_html5.c && ldconfig # OWASP CoreRuleSet mkdir -p /opt/coreruleset curl -fsSL https://github.com/coreruleset/coreruleset/archive/refs/tags/v4.26.0.tar.gz \ | tar -xz --strip-components=1 -C /opt/coreruleset # optional native scanners (graceful fallback to Lua if missing) g++ -shared -fPIC -O2 -std=c++17 -o /usr/local/lib/libka_re2.so src/libka_re2/ka_re2.cc -lre2 gcc -shared -fPIC -O2 -o /usr/local/lib/libka_ac.so src/libka_ac/ka_ac.c && ldconfig
Then wire Kong:
- Add
karnatopluginsinkong.conf(plugins = bundled,karna). - Set the PCRE cap:
KONG_NGINX_HTTP_LUA_REGEX_MATCH_LIMIT=100000. - Expose the
KARNA_*env vars to nginx workers viaKONG_NGINX_MAIN_INCLUDEpointing at a snippet likedocker/main-env.conf(nginx wipes the environment by default — see Environment variables). - Make the audit-log directory writable by the Kong worker user:
chown -R kong:kong /usr/local/openresty/nginx/logs. kong reload.
KARNA_LIBKA_RE2_SO, KARNA_LIBKA_AC_SO, KARNA_LIBINJECTION_SO, KARNA_CRS_PATH). Missing native libs never cause a silent drop — the engine falls back to the pure-Lua path.Attach Karna to a service
Declaratively in kong.yml (DB-less):
_format_version: "3.0" services: - name: my-app url: http://my-backend:8080 # your existing app routes: - name: my-app paths: ["/"] plugins: - name: karna config: engine_blocking_mode: false # detection-only to start paranoia_level: 1 auditlog_enabled: true
Or via the Admin API on a running Kong:
curl -X POST http://localhost:8001/services/<service_id>/plugins \ -H "Content-Type: application/json" \ -d '{ "name": "karna", "config": { "engine_blocking_mode": false, "paranoia_level": 1, "auditlog_enabled": true } }'
Run detection-only first
Always start with engine_blocking_mode: false. In this mode Karna evaluates every rule and writes the matches to the audit log, but never blocks. Watch the log against real traffic, tune away false positives with rule overrides and exceptions (see Writing rules), then flip engine_blocking_mode to true once you trust the result.