Kong AI Gateway — Unified Architecture

ARCHITECTURE SUMMARY

Kong AI Gateway — Unified Architecture

Single Ingress Point for All AI Model and MCP Traffic

Mission

Every AI interaction in the enterprise — app-to-model, agent-to-agent, agent-to-tool — flows through one gateway. No exceptions, no direct provider calls, no shadow credentials. This document ties together the four pillars of the architecture.

1. Single Ingress Point

All apps, agents, and MCP clients hit one endpoint family on Kong, never a provider directly. This is the architectural premise everything else depends on: if traffic can bypass the gateway, none of the governance below actually holds.

2. Credential Governance

  • Every provider key (Anthropic, Bedrock, OpenAI, internal APIs, MCP servers) lives in a vault, never in app code or Kong config.
  • Agents authenticate to Kong with their own Consumer credential — an identity Kong owns and can revoke independently of the underlying provider key.
  • Kong resolves the real credential at request time and injects it server-side. A leaked client-side key exposes nothing about the provider account behind it.
  • One Consumer model covers both LLM and MCP auth (OAuth2 for MCP), so access governance and credential governance are the same system.

3. MCP Registry & Gateway

  • The MCP Registry (Konnect Catalog, tech preview) catalogs approved MCP servers — owner, purpose, status — so agents discover tools in one place instead of hardcoding server URLs.
  • The AI MCP Proxy plugin fronts internal servers (passthrough), converts REST APIs into tools (conversion), or aggregates multiple servers into one endpoint (listener).
  • Tool-level ACLs gate both discovery and invocation, so a Consumer’s permissions extend down to individual tools, not just “can call MCP or not.”

4. Multi-Provider Failover

  • AI Proxy Advanced’s priority algorithm ranks providers into tiers (e.g. Anthropic → Bedrock → OpenAI). The top tier takes all traffic while healthy; the balancer only spills to the next tier on failure.
  • Active and passive health checks on the Upstream detect a degraded provider and flip targets automatically — no manual intervention during an outage.
  • Each tier still uses its own vault-backed credential, since Bedrock’s SigV4 auth, Anthropic’s API key, and OpenAI’s bearer token are structurally different.

5. Observability — The Thread Through All Three

  • Metrics, audit logs, and cost data are captured centrally, keyed to Consumer identity, not to whichever provider or MCP server actually served the request.
  • Failover events, tool invocations, and credential resolutions all land in the same logging/alerting pipeline, so “who called what, through which path, at what cost” is answerable from one place.

The Four Pillars at a Glance

Credential Governance Vault-backed keys, Consumer-level auth, server-side injection.MCP Registry & Gateway Catalog of approved servers, tool-level ACLs, proxy modes.Multi-Provider Failover Priority groups, health checks, automatic tier fallback.Observability Unified metrics, audit logs, cost tracking, failover alerts.

Why This Design Holds Together

Take any pillar away and the “single ingress point” claim weakens:

  • No credential governance → the gateway is a pass-through, not a security boundary.
  • No MCP registry/gateway → agents discover and call tools outside Kong’s visibility.
  • No failover → a single provider outage becomes a company-wide AI outage.
  • No shared observability → incidents can’t be traced back to an owner or a root cause.

Together, they turn “Kong is where AI traffic goes” into “Kong is where AI traffic is governed” — which is the actual job of the architect role.

on-prem Kong AI Gateway implementation

I would implement it from scratch in a controlled POC first, using Kong Gateway Enterprise 3.16 + PostgreSQL + Ollama, so the whole AI path can run on-prem without needing an external LLM API. Once that works, replace/augment Ollama with Azure OpenAI, OpenAI, vLLM, etc.

Kong’s current self-managed AI Gateway model uses standard Services + Routes + AI plugins; for multiple providers/models, the main plugin is ai-proxy-advanced. That plugin requires an AI license. Kong Docs

1. Target architecture

Start with this:

                 Client / Application
|
| HTTPS
v
+----------------+
| Kong |
| AI Gateway |
| |
| :8000 Proxy |
| :8001 Admin |
+-------+--------+
|
AI Proxy Advanced
|
v
+---------------+
| Ollama |
| :11434 |
+-------+-------+
|
v
Qwen/Llama

+---------------+
| PostgreSQL |
| :5432 |
+---------------+


For a lab, I’d use three Ubuntu 24.04 VMs:

kong01 4 vCPU 8 GB RAM
postgres01 2 vCPU 4 GB RAM
ollama01 8+ vCPU 16+ GB RAM

GPU on ollama01 is preferable but isn’t required for basic testing.


2. Install PostgreSQL

On postgres01:

sudo apt update
sudo apt install postgresql postgresql-contrib -y

Create Kong DB/user:

sudo -u postgres psql

Then:

CREATE USER kong WITH PASSWORD 'StrongKongPassword';
CREATE DATABASE kong OWNER kong;
GRANT ALL PRIVILEGES ON DATABASE kong TO kong;
\q

Configure PostgreSQL to accept your Kong server.

Edit:

sudo vi /etc/postgresql/*/main/postgresql.conf

Set:

listen_addresses = '*'

Then:

sudo vi /etc/postgresql/*/main/pg_hba.conf

For example:

host kong kong 192.168.10.0/24 scram-sha-256

Restart:

sudo systemctl restart postgresql
sudo systemctl enable postgresql

Test from Kong VM:

psql -h postgres01 -U kong -d kong

3. Install Kong Gateway

Kong currently documents self-managed Gateway 3.16.0.0 packages for Ubuntu. Kong Docs

On kong01:

sudo apt update
sudo apt install -y curl gnupg

Add Kong repository:

curl -1sLf \
"https://packages.konghq.com/public/gateway-316/gpg.998DFF461A62FF7C.key" \
| gpg --dearmor \
| sudo tee /usr/share/keyrings/kong-gateway-316-archive-keyring.gpg \
> /dev/null

For Ubuntu 24.04/Noble:

curl -1sLf \
"https://packages.konghq.com/public/gateway-316/config.deb.txt?distro=ubuntu&codename=noble" \
| sudo tee /etc/apt/sources.list.d/kong-gateway-316.list

Then:

sudo apt update
sudo apt install kong-enterprise-edition=3.16.0.0

Verify:

kong version

Expected roughly:

3.16.0.0

4. Configure Kong

Edit:

sudo vi /etc/kong/kong.conf

Basic lab configuration:

database = postgres
pg_host = postgres01
pg_port = 5432
pg_user = kong
pg_password = StrongKongPassword
pg_database = kong
proxy_listen = 0.0.0.0:8000
proxy_listen_ssl = 0.0.0.0:8443 ssl
admin_listen = 0.0.0.0:8001
admin_listen_ssl = 0.0.0.0:8444 ssl
status_listen = 0.0.0.0:8100
admin_gui_listen = 0.0.0.0:8002
admin_gui_ssl_listen = 0.0.0.0:8445

Do not expose 8001/8002 externally in production.


5. Add the Kong Enterprise / AI license

AI Proxy Advanced is an AI-license-required plugin. Kong Docs

Your license normally gets configured securely rather than embedded directly into scripts.

Confirm Kong sees the relevant plugins:

kong config parse /etc/kong/kong.conf

Later you can also check:

curl http://localhost:8001/plugins/enabled

Look for:

ai-proxy
ai-proxy-advanced
ai-prompt-guard
ai-rate-limiting-advanced
...

6. Bootstrap the Kong database

Run:

sudo -u kong kong migrations bootstrap \
-c /etc/kong/kong.conf

Then:

sudo kong start -c /etc/kong/kong.conf

Check:

curl http://localhost:8001/status

And:

curl http://localhost:8001

7. Install Ollama

Now create the local AI backend.

On ollama01, install Ollama using its supported installation method for your OS.

After installation verify:

systemctl status ollama

It normally listens on:

11434

You need it reachable from Kong:

kong01
|
| TCP 11434
v
ollama01

Test connectivity from Kong:

curl http://ollama01:11434/api/tags

You should receive JSON.


8. Pull an LLM

For the current Kong example, Kong documents a local Qwen 3 model using Ollama. Kong Docs

On Ollama:

ollama pull qwen3

Check:

ollama list

You should see:

NAME
qwen3

Test Ollama directly first.

For example:

curl http://ollama01:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
"model":"qwen3",
"messages":[
{
"role":"user",
"content":"What is Kong Gateway?"
}
]
}'

This is important: make Ollama work before introducing Kong.


9. Create the Kong AI Service

Create a Service:

curl -X POST http://localhost:8001/services \
--data name=ai-service \
--data url=http://ollama01:11434

Verify:

curl http://localhost:8001/services/ai-service

10. Create the AI Route

Create:

curl -X POST \
http://localhost:8001/services/ai-service/routes \
--data name=ai-chat-route \
--data 'paths[]=/ai/chat'

Check:

curl http://localhost:8001/routes

You now have:

Client
|
v
http://kong01:8000/ai/chat
|
v
ai-service

But we haven’t added AI translation yet.


11. Enable AI Proxy Advanced

This is the important part.

Attach ai-proxy-advanced to the route:

curl -X POST \
http://localhost:8001/routes/ai-chat-route/plugins \
-H "Content-Type: application/json" \
-d '{
"name": "ai-proxy-advanced",
"config": {
"targets": [
{
"route_type": "llm/v1/chat",
"model": {
"provider": "ollama",
"name": "qwen3",
"options": {
"upstream_url": "http://ollama01:11434"
}
}
}
]
}
}'

This configuration matches Kong’s documented Ollama/Qwen AI Proxy Advanced pattern. Kong Docs

Check it:

curl \
http://localhost:8001/routes/ai-chat-route/plugins

12. Test through Kong

Now the important test.

Instead of calling:

Ollama directly

you call:

Kong

Example:

curl -X POST \
http://kong01:8000/ai/chat \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": "Explain what an API gateway does."
}
]
}'

Flow:

curl
|
v
Kong :8000
|
Route
|
AI Proxy Advanced
|
provider = ollama
|
model = qwen3
|
v
Ollama :11434
|
v
Qwen

At this point you have built your first working Kong AI Gateway.


13. Add API authentication

Don’t leave:

/ai/chat

public.

For the initial lab you can use key-auth:

curl -X POST \
http://localhost:8001/routes/ai-chat-route/plugins \
--data name=key-auth

Create Consumer:

curl -X POST \
http://localhost:8001/consumers \
--data username=ai-application

Create key:

curl -X POST \
http://localhost:8001/consumers/ai-application/key-auth \
--data key=my-secret-ai-key

Test without key:

curl http://kong01:8000/ai/chat

Should return:

401 Unauthorized

Use:

curl -X POST \
http://kong01:8000/ai/chat \
-H "apikey: my-secret-ai-key" \
-H "Content-Type: application/json" \
-d '{
"messages":[
{
"role":"user",
"content":"Explain Kong AI Gateway."
}
]
}'

For production, given your existing environment, I’d replace key-auth with Ping Identity + OIDC.


14. Enable Prometheus AI metrics

Kong’s Prometheus plugin supports AI-specific metrics including requests, token consumption, provider/model information, LLM latency and cost information where available. Set:

ai_metrics = true

Kong documents AI metrics from Gateway 3.8+, including consumer attribution in newer releases. Kong Docs

Enable globally:

curl -X POST \
http://localhost:8001/plugins \
--data name=prometheus \
--data config.status_code_metrics=true \
--data config.latency_metrics=true \
--data config.ai_metrics=true

Check:

curl http://kong01:8100/metrics

Useful metrics will include Kong latency plus AI-specific measurements.

Kong recommends the Status API /metrics endpoint when available rather than exposing the Admin API to Prometheus. Kong Docs


15. Prometheus configuration

On Prometheus:

scrape_configs:
- job_name: "kong-ai-gateway"
scrape_interval: 15s
static_configs:
- targets:
- "kong01:8100"

Restart/reload Prometheus.

Check:

Status → Targets

Kong should show:

UP

16. Grafana dashboard

I would build panels for:

AI Gateway Requests/sec
Input Tokens/sec
Output Tokens/sec
Kong latency:
p50
p95
p99
LLM latency:
p50
p95
p99
HTTP:
2xx
4xx
429
5xx
AI provider
AI model
Consumer
Cache hit/miss

For Kong p95:

histogram_quantile(
0.95,
sum by (le) (
rate(kong_kong_latency_ms_bucket[5m])
)
)

And p99:

histogram_quantile(
0.99,
sum by (le) (
rate(kong_kong_latency_ms_bucket[5m])
)
)

17. Add Azure OpenAI later

Once Ollama works, adding Azure OpenAI is easy.

The architecture becomes:

                       Kong AI Gateway
                              |
             +----------------+--------------+
             |                               |
             v                               v
          Ollama                       Azure OpenAI
          Qwen3                         GPT model
        On-premise                       Azure

Kong’s documented Azure configuration uses:

provider: azure
auth:
header_name: api-key
model:
name: gpt-4o
options:
azure_instance: ...
azure_deployment_id: ...
azure_api_version: ...
``` :chatgpt-content-reference{index="7"}
---
# 18. Then introduce AI security controls
Your eventual plugin chain should look like:
```text
Client
|
v
F5
|
v
Kong
|
+-- OIDC / Ping Identity
|
+-- ACL / Consumer Group
|
+-- AI Prompt Guard
|
+-- AI Rate Limiting Advanced
|
+-- AI Semantic Cache
|
+-- AI Proxy Advanced
|
+-- Prometheus
|
+-- HTTP Log
|
v
AI Provider

Don’t add all of those on day one.

Use this order:

1 Kong
2 PostgreSQL
3 Ollama
4 AI Proxy Advanced
5 Validate AI request
6 Authentication
7 Prometheus/Grafana
8 Logging/ELK
9 Prompt Guard
10 AI Rate Limiting
11 Redis
12 Semantic Cache
13 Multiple LLM providers
14 MCP

19. Production architecture

After your single-node POC works, I would move to this:

                         Applications
                              |
                              |
                         +----v----+
                         |   F5    |
                         |   VIP   |
                         +----+----+
                              |
                    +---------+---------+
                    |                   |
                +---v---+           +---v---+
                | DP-01 |           | DP-02 |
                | Kong  |           | Kong  |
                +---+---+           +---+---+
                    |                   |
                    +---------+---------+
                              |
                 AI Providers / Models
                   /        |       \
                  /         |        \
             Ollama       vLLM     Azure OpenAI


          Control plane – NOT in request path

             +-----------+     +-----------+
             | Kong CP01 |     | Kong CP02 |
             +-----+-----+     +-----+-----+
                   \                 /
                    \               /
                     +------v------+
                     | PostgreSQL  |
                     +-------------+


                     +-------------+
                     |    Redis    |
                     +-------------+
                       /         \
                Rate limit    AI cache


DP01/DP02
   |
   +------ Prometheus ------ Grafana
   |
   +------ Filebeat -------- Logstash
                              |
                              v
                         Elasticsearch
                              |
                            Kibana

Kong hybrid mode explicitly separates the roles: the Control Plane uses PostgreSQL and distributes configuration, while the Data Planes run DB-less and proxy traffic. Kong Docs

I would target this configuration for production deployment:

2 x Kong Control Plane
4 vCPU
8–16 GB RAM
2 x Kong Data Plane
8 vCPU
16 GB RAM
1 x PostgreSQL HA service/cluster
1–3 x Redis nodes depending on HA requirements
2 x F5 pool members initially
Prometheus/Grafana
ELK
Ollama/vLLM GPU nodes if running models internally

The important design principle is:

Kong should not perform inference. Kong handles authentication, routing, governance, rate limits, caching, security, metrics and provider abstraction; Ollama/vLLM/Azure/OpenAI performs the actual model inference.

For your environment, I would therefore build the first working POC as:

Ubuntu 24.04 → PostgreSQL → Kong 3.16 → Ollama/Qwen → ai-proxy-advanced → key-auth → Prometheus/Grafana, and only after that convert it to F5 → 2 Kong DP → Ollama/Azure OpenAI with 2 Kong CP + PostgreSQL. Kong Docs

Kong AI Gateway — Plugin Catalog

Kong’s AI capabilities ship as a set of plugins on top of the core Kong Gateway/Konnect data plane, rather than a separate product. The first six AI plugins shipped in Kong Gateway 3.6 (Feb 2024) as open source; more advanced governance plugins were added later and require Kong Enterprise or Konnect licensing.

Traffic proxying & routing

PluginWhat it does
AI ProxyThe base plugin. Normalizes one request format across providers (OpenAI, Anthropic, Azure, Cohere, Bedrock, Gemini, etc.), translates it to the target’s native format, and transforms the response back. Open source.
AI Proxy AdvancedMulti-target version of AI Proxy — proxies to several providers/models at once and adds load balancing. This is what powers the failover setup we built earlier.
AI MCP ProxyFronts MCP servers (passthrough, conversion, or listener mode), covered in the registry/gateway duty above.
AI MCP OAuth2OAuth2 resource-server behavior specifically for MCP traffic.
AI A2A ProxyRoutes Agent2Agent (A2A) protocol traffic through Kong, with the same per-consumer auth and rate-limiting controls as other AI routes.

Load balancing algorithms (inside AI Proxy Advanced)

Configured via the Upstream entity, not separate plugins:

  • Round-robin (weighted) — proportional traffic split by weight.
  • Consistent-hashing — sticky sessions via a hashed header (default X-Kong-LLM-Request-ID).
  • Lowest-latency — routes to whichever target is currently fastest.
  • Lowest-usage — routes based on token/cost usage, including a cost option added to the usage strategy.
  • Priority — tiered failover (what we configured for Anthropic → Bedrock → OpenAI).
  • Semantic — routes prompts to domain-specialized models based on embedding similarity, with distance_metric and threshold controlling match sensitivity.
  • 3.13+ added health checks and a circuit breaker for the load balancer itself, plus failover/circuit-breaking for semantic routing specifically.

Governance & safety

PluginWhat it does
AI Prompt GuardBlocks or allows prompts by pattern/keyword rules.
AI Semantic Prompt GuardSame idea, but matches by embedding similarity rather than literal pattern — catches paraphrased attempts at a blocked topic. Enterprise.
AI Prompt DecoratorInjects or modifies system/user prompt content before it reaches the model (e.g. enforcing a system prompt).
AI Request/Response TransformerGeneral-purpose payload transformation for AI requests and responses.
AI Rate Limiting AdvancedRate limits by token count and cost, not just request count — this is the plugin underpinning the per-team quota story from the credential-governance duty. Enterprise.

Cost & performance

PluginWhat it does
AI Semantic CacheCaches responses by embedding similarity so repeated/similar prompts skip the model call entirely. Backed by a vector store (Redis and others). Enterprise.
AI RAG InjectorPulls relevant context from a vector store and injects it into the prompt for retrieval-augmented generation.

Observability

  • Prometheus plugin was extended with AI-specific metrics (token counts, cost, latency, MCP call volume) — this is what feeds the shared observability layer from the architecture summary.

Licensing note

Per Kong’s own docs and third-party comparisons: AI Proxy, AI Proxy Advanced, AI Prompt Guard, and AI Prompt Decorator are open source. AI Rate Limiting Advanced, AI Semantic Cache, AI Semantic Prompt Guard, and AI MCP Proxy sit behind Kong Enterprise/Konnect licensing. Confirm current tier gating against Kong’s plugin hub for your specific version, since this has shifted release to release.

Good — pulled the current plugin hub listing directly. Here’s the accurate, up-to-date table, tagged by license tier and mapped to the four pillars from the architecture doc.

AI Plugin Tier Table (Kong Plugin Hub, current)

Free / open source (no AI license required)

PluginWhat it does
AI ProxyBase multi-provider proxy and normalization
AI Prompt GuardPattern-based allow/deny list for prompts
AI Prompt DecoratorPrepends/appends messages to chat history
AI Prompt TemplateFill-in-the-blank prompt templates
AI Request TransformerLLM-based transform of the client request body
AI Response TransformerLLM-based transform of the upstream response

AI License Required (Enterprise/Konnect AI Gateway tier)

PluginWhat it does
AI Proxy AdvancedMulti-target proxy + load balancing/failover
AI Rate Limiting AdvancedToken/cost-based rate limiting
AI Semantic CacheEmbedding-based response caching
AI Semantic Prompt GuardEmbedding-based topic allow/deny
AI Semantic Response GuardBlocks/permits by similarity to known responses
AI PII SanitizerRedacts sensitive data in request/response bodies
AI Prompt CompressorShrinks prompts to cut cost/latency
AI RAG InjectorInjects vector-store content for RAG
AI MCP ProxyMCP server proxying, conversion, aggregation
AI MCP OAuth2OAuth2 auth for MCP servers
AI A2A ProxyGovernance for Agent-to-Agent protocol traffic
AI LLM as JudgeEvaluates/optimizes model output quality
AI AWS Guardrails / AI Azure Content Safety / AI GCP Model ArmorCloud-native guardrail integrations
AI Custom GuardrailBring-your-own third-party guardrails service
AI Lakera GuardLakera Guard safety-policy enforcement

Third-party (separate vendor licensing)
CrowdStrike Falcon AIDR (Request/Response/MCP), Harness AI Security, Noma Runtime Protection, Prisma AIRS, Skyflow De-identify, Straiker (+ Coding Agent variants), Impart Security, VeriKnox.

Mapped to the four architecture pillars

PillarPlugins that implement it
Credential GovernanceAI Proxy / AI Proxy Advanced (vault-referenced auth blocks); AI PII Sanitizer for data leaving the gateway
MCP Registry & GatewayAI MCP Proxy, AI MCP OAuth2
Multi-Provider FailoverAI Proxy Advanced (priority/weighted/semantic/lowest-latency/lowest-usage load balancing, plus 3.13+ health checks and circuit breaker)
ObservabilityPrometheus (extended with AI metrics), OpenTelemetry, AI LLM as Judge for quality tracking
(Guardrails — a fifth pillar worth adding)AI Prompt Guard, AI Semantic Prompt Guard, AI Semantic Response Guard, AI AWS/Azure/GCP Guardrails, AI Custom Guardrail, AI Lakera Guard

One correction from earlier: I’d said AI Prompt Guard and AI Prompt Decorator might be gated — they’re actually free/open source. AI Proxy Advanced, AI Rate Limiting Advanced, AI Semantic Cache, AI Semantic Prompt Guard, AI MCP Proxy and AI MCP OAuth2 are the ones that need the AI license.

I’d also flag that Guardrails has grown into its own real pillar — with cloud-native integrations (AWS/Azure/GCP) plus third-party options (Lakera, CrowdStrike, Straiker) — separate from what I’d folded into “credential governance” earlier.

Kong – full mini project folder

Here’s a full mini project folder for Kong that you can copy as-is.

It uses Kong Gateway in DB-less mode, so all config lives in one declarative kong.yml file. That mode is a good fit for CI/CD and Git-managed config, but the Admin API is effectively read-only for config changes in this setup. (Kong Docs)

Folder structure

kong-mini-project/
├── app/
│ ├── package.json
│ └── server.js
├── kong/
│ └── kong.yml
├── .dockerignore
├── Dockerfile
└── compose.yml

1) app/package.json

{
"name": "kong-mini-project",
"version": "1.0.0",
"description": "Node app behind Kong Gateway",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"license": "MIT"
}

2) app/server.js

const http = require("http");
const PORT = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
if (req.url === "/healthz") {
res.writeHead(200, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ ok: true }));
}
const body = {
ok: true,
message: "Hello from app behind Kong",
method: req.method,
url: req.url,
host: req.headers.host,
time: new Date().toISOString()
};
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify(body, null, 2));
});
server.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
});

3) Dockerfile

FROM node:20-alpine
WORKDIR /app
COPY app/package.json ./
RUN npm install --omit=dev
COPY app/server.js ./
ENV PORT=3000
EXPOSE 3000
CMD ["npm", "start"]

4) .dockerignore

node_modules
npm-debug.log
.git
.github

5) kong/kong.yml

This is the heart of the project. It defines:

  • one upstream Service
  • one public Route
  • a key-auth plugin
  • a rate-limiting plugin
  • one Consumer with an API key

Kong’s declarative config format supports entities like Services, Routes, Consumers, and Plugins in DB-less mode. The Key Auth plugin can require API keys, and the Rate Limiting plugin can throttle requests by time window such as per minute. When authentication is present, rate limiting uses the authenticated Consumer identity. (Kong Docs)

_format_version: "3.0"
services:
- name: app-service
url: http://app:3000
routes:
- name: app-route
paths:
- /api
protocols:
- http
- https
plugins:
- name: key-auth
service: app-service
config:
key_names:
- apikey
- name: rate-limiting
service: app-service
config:
minute: 5
policy: local
consumers:
- username: demo-client
keyauth_credentials:
- key: super-secret-demo-key

A note on policy: local: that works well for a single local node, but Kong notes that plugins needing shared database state do not fully function in DB-less mode, so this is best for learning or single-node setups rather than clustered distributed quotas. (Kong Docs)

6) compose.yml

Kong’s Docker docs support running Kong with Docker Compose, and the read-only Docker Compose guide for DB-less mode uses KONG_DATABASE=off plus KONG_DECLARATIVE_CONFIG pointing to the config file. (Kong Docs)

services:
kong:
image: kong:3.10
environment:
KONG_DATABASE: "off"
KONG_DECLARATIVE_CONFIG: /kong/declarative/kong.yml
KONG_PROXY_ACCESS_LOG: /dev/stdout
KONG_ADMIN_ACCESS_LOG: /dev/stdout
KONG_PROXY_ERROR_LOG: /dev/stderr
KONG_ADMIN_ERROR_LOG: /dev/stderr
KONG_ADMIN_LISTEN: 0.0.0.0:8001
ports:
- "8000:8000" # public proxy
- "8001:8001" # admin api (read-only for config in DB-less mode)
volumes:
- ./kong/kong.yml:/kong/declarative/kong.yml:ro
app:
build:
context: .
dockerfile: Dockerfile

7) Run it

docker compose up -d --build

Then test it.

Without an API key, access should fail because the route is protected by the Key Auth plugin. (Kong Docs)

curl -i http://localhost:8000/api

With the API key in a header, it should succeed. Kong’s Key Auth plugin supports reading keys from headers, query parameters, or request body, depending on config. (Kong Docs)

curl -i \
-H "apikey: super-secret-demo-key" \
http://localhost:8000/api

You can also use a query string:

curl -i "http://localhost:8000/api?apikey=super-secret-demo-key"

8) Test rate limiting

The plugin is set to 5 requests per minute, so the sixth quick request should return 429. Kong’s rate-limiting plugin supports time windows including seconds, minutes, hours, days, months, and years. (Kong Docs)

for i in {1..6}; do
curl -s -o /dev/null -w "%{http_code}\n" \
-H "apikey: super-secret-demo-key" \
http://localhost:8000/api
done

9) Useful checks

See running containers:

docker compose ps

Follow Kong logs:

docker compose logs -f kong

Follow app logs:

docker compose logs -f app

Read the service list from the Admin API:

curl http://localhost:8001/services

In DB-less mode, that Admin API is useful for inspection, but Kong’s docs say you cannot use it for normal write-based configuration management because the declarative file is the source of truth. (Kong Docs)

10) What makes this different from Traefik

With Traefik, the main workflow was “discover containers and route traffic to them.” With Kong, the model is “define Services and Routes, then attach policy plugins like auth and rate limiting.” Kong’s docs emphasize entities such as Services, Routes, Consumers, Upstreams, and Plugins as the core gateway model. (Kong Docs)

So in practice:

  • Traefik is great for app routing and reverse proxying.
  • Kong is better when you want API-specific control like identity, quotas, and policy.

11) Resume line

Built a containerized API behind Kong Gateway in DB-less mode using declarative configuration, API key authentication, and per-consumer rate limiting.

12) Best next upgrade

The strongest next step is to add JWT auth or request transformation, because those show off Kong as an API gateway rather than just a reverse proxy. Kong’s plugin ecosystem is one of its main strengths. (Kong Docs)

KONG

Got it — here’s a clean, practical way to wire Client → Cloudflare → F5 → Kong → Upstream so your normal Kong flow
Client → [Kong Route matched] → [Service invoked] → Upstream API works end-to-end.


0) Topology (recommended)

Client ─TLS─> Cloudflare ─TLS─> F5 VIP ─HTTP─> Kong (8000) ─(HTTP/HTTPS)─> Upstream

  • Cloudflare terminates client TLS + WAF/bot/DDOS.
  • F5 is your “origin” for Cloudflare, then load balances across Kong nodes.
  • Kong routes/plugins/auth, then proxies to your upstream.

You can also do F5→Kong over HTTPS (8443). Start with HTTP (simpler), add re-encryption later.


1) Cloudflare (edge) setup

  1. DNS: api.example.com → orange-cloud (proxied) to your F5 public IP.
  2. SSL/TLS: set mode Full (strict).
  3. Authenticated Origin Pull (AOP):
    • Enable it in Cloudflare.
    • On F5, require the Cloudflare client cert (see F5 step) so only CF can hit your VIP.
  4. Origin server certificate (on F5): either
    • a normal public cert (LetsEncrypt, etc.), or
    • a Cloudflare Origin Certificate (valid only to CF; fine if you never bypass CF).
  5. API cache rules: bypass cache for /api/*, enable WebSockets if you use them.

2) F5 LTM (VIP to Kong) essentials

Virtual server (HTTPS on 443) → pool (Kong nodes on 8000)

  • Client SSL profile: present your cert (public or CF Origin Cert).
  • (Optional but recommended) verify Cloudflare client cert for AOP:
    import Cloudflare Origin Pull CA on F5 and set it as Trusted CA; require client cert.
  • HTTP profile: enable; Insert X-Forwarded-For; preserve headers.
  • OneConnect: enable for keep-alives to Kong.
  • Pool members: all Kong nodes, port 8000 (or 8443 if you re-encrypt).
  • Health monitor: HTTP GET to Kong status (see Kong step).

Header hygiene (iRule – optional, if you want to be explicit):

when HTTP_REQUEST {
  # Preserve real client IP from Cloudflare into X-Forwarded-For
  if { [HTTP::header exists "CF-Connecting-IP"] } {
    set cfip [HTTP::header value "CF-Connecting-IP"]
    if { [HTTP::header exists "X-Forwarded-For"] } {
      HTTP::header replace "X-Forwarded-For" "[HTTP::header value X-Forwarded-For], $cfip"
    } else {
      HTTP::header insert "X-Forwarded-For" $cfip
    }
  }
  HTTP::header replace "X-Forwarded-Proto" "https"
}

(Or just enable “X-Forwarded-For: append” in the HTTP profile and set XFP via policy.)


3) Kong Gateway settings (behind F5)

Environment (docker-compose/env vars):

KONG_PROXY_LISTEN=0.0.0.0:8000
# Trust only your F5 addresses/CIDRs (do NOT trust 0.0.0.0/0)
KONG_TRUSTED_IPS=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,<F5_VIP_or_SNATs>
KONG_REAL_IP_HEADER=X-Forwarded-For
KONG_REAL_IP_RECURSIVE=on
# helpful during testing
KONG_HEADERS=latency_tokens
# health endpoint for F5 monitor (internal only)
KONG_STATUS_LISTEN=0.0.0.0:8100

F5 health monitor target (HTTP):

  • URL: http://<kong-node>:8100/status
  • Expect: 200 (Kong’s status port; safe to expose internally)

Define Service/Route (example):

# Service to your upstream (HTTP)
curl -sX POST :8001/services \
  -d name=orders-svc \
  -d host=tomcat-app \
  -d port=8080 \
  -d protocol=http

# Route that matches your API path/host
curl -sX POST :8001/routes \
  -d service.name=orders-svc \
  -d hosts[]=api.example.com \
  -d paths[]=/v1

(If upstream is HTTPS, set protocol=https, port=443, and sni=upstream.host.)


4) Putting it together (request path)

  1. Client → https://api.example.com/v1/...
  2. Cloudflare terminates TLS, adds CF-Connecting-IP, forwards to F5.
  3. F5 validates CF client cert (AOP), appends XFF, sets X-Forwarded-Proto:https, LB to a Kong node.
  4. Kong trusts F5 IP, extracts the real client IP from XFF, matches Route (Host=api.example.com, path=/v1), invokes Service, proxies to Upstream.
  5. Response flows back; Kong adds latency headers (if enabled); F5 returns to CF; CF returns to client.

5) Testing (in layers)

  • Direct to Kong (bypass CF/F5) on the private network: curl -i -H 'Host: api.example.com' http://<kong-node>:8000/v1/ping -H 'Kong-Debug: 1'
  • Through F5 VIP (simulate Cloudflare off): curl -i -H 'Host: api.example.com' https://<f5-public-ip>/v1/ping --resolve api.example.com:<f5-public-ip>:443
  • Through Cloudflare (real path): curl -i https://api.example.com/v1/ping -H 'Kong-Debug: 1'

Check headers:

  • X-Kong-Upstream-Latency (upstream time)
  • X-Kong-Proxy-Latency (Kong internal)
  • Logs in Kong show client_ip = real client IP (not F5/CF) if trusted IPs are correct.

6) Observability (recommended)

  • Kong plugins:
    • prometheus (metrics), correlation-id (X-Request-ID), http-log or file-log → ELK.
  • F5: request logging profile to ELK; LTM stats.
  • Cloudflare: Security events/Edge logs (if plan allows).

7) Common gotchas (and quick fixes)

  • Client IP shows F5/Cloudflare → set KONG_TRUSTED_IPS, REAL_IP_*; ensure F5 appends XFF and passes CF-Connecting-IP.
  • OIDC header lost → make sure F5 policy does not strip Authorization.
  • Wrong redirects / mixed content → ensure X-Forwarded-Proto: https reaches Kong & upstream.
  • “Server busy” / spikes → raise F5 OneConnect pool, ensure Kong backlog/somaxconn, keepalive to upstream.
  • Health checks hitting Admin API → use KONG_STATUS_LISTEN (8100) instead, not port 8001 (Admin).

Cloudflare → F5 → Kong API stack

Here’s the clean mental model for a Cloudflare → F5 → Kong API stack, plus the key headers/TLS choices and the minimum config knobs so it “just works.”

1) The traffic flow (happy path)

Client ─(HTTPS/HTTP2/3)→ Cloudflare ─(TLS to origin)→ F5 VIP ─(HTTP/HTTPS)→ Kong cluster ─→ Upstream services

  1. Cloudflare terminates the client TLS (always, if the orange-cloud proxy is on).
    • Applies WAF, DDoS, bot rules, rate limits, geo rules, etc.
    • Forwards to your F5 VIP as the “origin”.
  2. F5 LTM receives Cloudflare’s request.
    • Usually terminates TLS again (re-encrypt to Kong or send plain HTTP on the inside).
    • Load-balances across Kong nodes (pool members in Zone A/B).
  3. Kong Gateway routes by Host/path to your backend (service), runs plugins (OIDC, rate-limit, etc.), and proxies to the upstream.

2) TLS choices (pick one per hop)

Cloudflare → F5 (origin TLS):

  • Set Cloudflare SSL mode to Full (strict).
  • Enable Authenticated Origin Pull so only Cloudflare can hit F5.
  • On F5, trust Cloudflare’s Origin Pull CA and require client cert.

F5 → Kong:

  • Simple: terminate on F5 and send HTTP to Kong on the private VLAN.
  • End-to-end TLS: client-SSL on F5, server-SSL from F5 to Kong (re-encrypt), SNI kong.internal (or node name).

Kong → Upstream:

  • Match your upstream: protocol=http|https, SNI if TLS, optionally mTLS to sensitive services.

3) Real client IP (do this or logs/limits will be wrong)

Cloudflare sets:

  • CF-Connecting-IP (client IP)
  • X-Forwarded-For (appends client IP)
  • X-Forwarded-Proto: https

F5 should preserve (not overwrite) X-Forwarded-For and pass X-Forwarded-Proto.

Kong must trust the proxy chain so it can compute the real client IP:

  • Set (env or kong.conf):
    • KONG_TRUSTED_IPS=<F5 private CIDRs or F5 VIPs> (don’t trust 0.0.0.0/0)
    • KONG_REAL_IP_HEADER=X-Forwarded-For
    • KONG_REAL_IP_RECURSIVE=on
  • Then client_ip in logs, rate-limit/correlation will be the actual user IP from Cloudflare.

If you prefer using Cloudflare’s header explicitly, you can have F5 copy CF-Connecting-IP into the leftmost position of X-Forwarded-For.

4) Load balancing & health checks (avoid double “mystery” failover)

  • Cloudflare (optional LB): usually point it at a single F5 VIP per region and let F5 do node health.
  • F5 → Kong nodes: HTTP health monitor (e.g., GET /status/health on each Kong).
  • Kong → upstreams: use Kong Upstreams/Targets with active + passive health checks to eject bad app pods.

Pick one layer to be the source of truth per hop (Cloudflare LB or F5, Kong or upstream LB) to avoid contradictory decisions.

5) Protocols & connections

  • HTTP versions: client can be HTTP/2 or HTTP/3 to Cloudflare. Cloudflare→F5 is HTTP/1.1 or HTTP/2 (CF may downgrade). F5→Kong is typically HTTP/1.1.
  • Keep-alive: enable OneConnect on F5 and keep-alive to Kong to avoid connection churn.
  • WebSockets/gRPC: supported end-to-end; ensure Upgrade/HTTP2 is enabled through F5 and Kong Routes/Services.

6) Minimal config snippets

F5 (HTTP profile / header handling):

  • Enable “Insert X-Forwarded-For” (or an iRule to append not overwrite).
  • Preserve X-Forwarded-Proto = https.
  • If using Authenticated Origin Pull: client-SSL requires CF client cert; trust CF Origin CA.

Kong (env):

KONG_HEADERS=latency_tokens
KONG_TRUSTED_IPS=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16, &lt;your F5 VIPs/CIDRs&gt;
KONG_REAL_IP_HEADER=X-Forwarded-For
KONG_REAL_IP_RECURSIVE=on

Kong Service (HTTPS upstream with SNI):

protocol: https
host: api.internal.example
port: 443
tls_verify: true
sni: api.internal.example

Kong rate limiting behind proxies: use consumer or ip policy; with trusted IPs set, ip uses the real client.

7) Observability (what to turn on)

  • Cloudflare: (if plan allows) Edge logs / Security events (attack/waf/bot).
  • F5: LTM logs + request logging profiles; export to ELK.
  • Kong: enable Prometheus plugin, correlation-id, and http-log/file-log to ELK.
  • Make sure your ELK/Loki sees client_ip, X-Request-ID, service, route, upstream_status, latencies.{kong,proxy,request}.

8) Common pitfalls & quick fixes

  • Client IP shows F5/Cloudflare: set KONG_TRUSTED_IPS and KONG_REAL_IP_* as above; ensure F5 appends—not overwrites—X-Forwarded-For.
  • OIDC 401s behind CF/F5: your LB stripped Authorization. Validate with an echo upstream; ensure F5 leaves Authorization intact.
  • Mixed-content / wrong redirects: preserve X-Forwarded-Proto: https through to Kong and upstream so apps build HTTPS URLs.
  • Header too large (Set-Cookie): raise Kong Nginx proxy buffers if you see upstream sent too big header.
  • Double LB flaps: don’t health-check the same hop in both Cloudflare and F5 with different intervals/paths.

9) Example end-to-end (typical, secure)

  1. Cloudflare Full (strict) + Authenticated Origin Pull → F5 public VIP api.example.com:443.
  2. F5 terminates TLS, adds XFF if missing, passes X-Forwarded-Proto: https, LB to kongA:8000, kongB:8000.
  3. Kong trusts F5 IPs, pulls real client IP from XFF, runs OIDC/rate-limit, sends to upstream (HTTPS with SNI).
  4. Logs/metrics from all 3 land in ELK/Grafana.

Kong / our app is build using Java Spring Boot

When integrating certificates into Spring Boot, especially for mTLS, HTTPS, or secure inter-service communication, there are several important certificate handling considerations you should account for:


1. Keystore / Truststore Formats

StorePurposeCommon Format
KeystoreHolds your application’s private key + certJKS, PKCS12 (.p12 / .pfx)
TruststoreHolds trusted CA certs to verify clients or serversJKS, PKCS12

JKS is Java-native, but PKCS12 is preferred for modern apps (more portable + supports OpenSSL).

Example Spring Boot Config:

server.ssl.key-store=classpath:server.p12
server.ssl.key-store-password=changeit
server.ssl.key-store-type=PKCS12
server.ssl.trust-store=classpath:truststore.p12
server.ssl.trust-store-password=changeit
server.ssl.trust-store-type=PKCS12


2. Certificate Chain Requirements

Spring Boot expects:

  • Full certificate chain in the keystore if issued by an intermediate CA
  • Trusted root CA in the truststore (for mTLS)

🔸 Failure to include the full chain often results in handshake errors or “unable to find valid certification path” errors.


3. Protocol Configuration (TLS)

Spring Boot (via embedded Tomcat) uses TLS 1.2+ by default.

To restrict or specify:

server.ssl.enabled-protocols=TLSv1.2,TLSv1.3

Disable TLS 1.0/1.1 — they are deprecated and insecure.


4. Cipher Suites

Spring Boot (via Tomcat) negotiates secure ciphers by default.
You can explicitly define them:

server.ssl.ciphers=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,...

Use modern ciphers like ECDHE + AES_GCM.
Avoid RC4, 3DES, NULL, or EXPORT ciphers.


5. Mutual TLS (mTLS)

To require client certs:

server.ssl.client-auth=need

Modes:

  • none: default (no client cert)
  • want: optional client cert
  • need: mandatory client cert (for mTLS)

6. Generating Keystore & Truststore

Convert PEM to PKCS12:

openssl pkcs12 -export \
  -in client.crt \
  -inkey client.key \
  -certfile ca.crt \
  -out client-keystore.p12 \
  -name client

Then import trusted CA into truststore (if using JKS):

keytool -import -alias myca -file ca.crt -keystore truststore.jks


7. Spring Boot with Reverse Proxies (e.g., Kong, F5)

If TLS termination is done by Kong/F5 and Spring Boot sits behind it:

  • Use X-Forwarded headers: server.forward-headers-strategy=framework
  • Do not terminate TLS inside Spring unless you need end-to-end TLS.

Summary: What to Account For

AreaKey Considerations
FormatUse PKCS12 for best compatibility
TrustTruststore must contain root CA or intermediate
ChainInclude full cert chain in keystore
ProtocolEnable TLSv1.2+ only
CiphersUse strong, modern suites
mTLSSet client-auth=need + configure truststore
ProxyHandle X-Forwarded-* if behind Kong/F5

KONG 401 error caused by F5

F5 (BIG-IP) or any load balancer can cause a 401 Unauthorized error in Kong, depending on how it’s configured. Here’s how:


How F5 Can Cause 401 Errors in Kong

F5 MisconfigurationEffect on Kong
Strips Authorization headersKong never receives the token/key — authentication fails with 401.
Overwrites headers (like Host or X-Forwarded-*)Breaks routing or causes Kong to reject the request.
SSL Termination issuesOIDC or JWT validation fails due to invalid scheme or issuer mismatch.
Rewrites path incorrectlyKong cannot match the route, plugin doesn’t apply properly, or token is invalid.
Session persistence or cookie manipulationDisrupts OIDC or session-based auth flows.

How to Test if F5 is the Cause

  1. Bypass F5 (send request directly to Kong): curl -i http://<kong-IP>:8000/<route-path> \ -H "Authorization: Bearer <your-token>"
    • If this works and through F5 it fails → F5 is modifying/blocking something.
  2. Inspect headers from F5:
    • Add a logging plugin in Kong to dump all headers.
    • Use request-transformer or a custom plugin to inspect incoming headers.
  3. Check F5 HTTP Profile:
    • Ensure Authorization headers are not removed.
      • F5 → Virtual Server → HTTP Profile → Request Header Erase should not include Authorization.
  4. Enable debug logs in Kong:
    • Will show missing/malformed headers.

Fix Recommendations

  • Preserve Authorization headers in F5 config.
  • Ensure correct SSL termination and forwarding.
  • Keep route paths intact when forwarding.
  • Use F5 “passthrough” mode if possible for auth-related traffic.

KONG 401 & 400 error

If you’re getting 401 and 400 intermittently from the upstream service, that strongly suggests authentication-related issues, often tied to token forwarding, expiration, or format mismatch.


Quick Summary of Key Differences

StatusMeaningCommon Cause
401UnauthorizedMissing/invalid/expired credentials
400Bad RequestMalformed or incomplete request (e.g. OIDC token request)

Intermittent 401 + 400: Common Root Causes

1. Expired or Reused Tokens

  • Kong gets a token once, caches it, and keeps using it—but upstream expects a fresh one.
  • Especially common with client credentials or authorization code flows.

Solution:

  • Set token caching to short duration or disable it in the OIDC plugin: config: cache_ttl: 0 # Or a very short TTL like 5

2. Multiple Consumers with Invalid Secrets

  • One client (consumer) is configured correctly, others are not.
  • You see 401/400 when the bad client makes a request.

Solution:

  • Enable verbose logging in Kong: export KONG_LOG_LEVEL=debug kong reload Then correlate consumer_id with the error.

3. Kong Not Forwarding Tokens Correctly

  • Kong authenticates but doesn’t forward Authorization header to the upstream.
  • Some plugins strip headers by default.

Solution:

  • Add request-transformer plugin to pass the token: curl -X POST http://localhost:8001/services/YOUR_SERVICE/plugins \ --data "name=request-transformer" \ --data "config.add.headers=Authorization:Bearer $(jwt_token)"

🔸 4. OIDC Plugin Misconfiguration

If you’re using the OpenID Connect plugin:

  • grant_type, client_id, or redirect_uri may be wrong or missing intermittently.
  • Kong might request a new token but fail to pass a correct one.

Check:

  • Kong OIDC plugin config
  • Errors like: error=invalid_request error_description="Unsupported client authentication method"

How to Debug Effectively

  1. Set KONG_LOG_LEVEL=debug, reload Kong, and tail the logs: tail -f /usr/local/kong/logs/error.log
  2. Inspect Upstream Request:
    • Look for what headers/body Kong is sending.
    • Especially Authorization, Content-Type, and request body if OIDC is involved.
  3. Track Errors to a Specific Consumer:
    • Use consumer_id in the access log to trace.
    • Maybe only some consumers are misconfigured.
  4. Try Curling the Upstream Directly with the exact payload Kong sends (use Postman or curl): curl -X POST https://upstream/token \ -H "Authorization: Bearer <your_token>" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials&client_id=...&client_secret=..."

to check

  • Kong plugin configs (especially OIDC/JWT)
  • A few lines from Kong’s debug logs showing the upstream request/response
  • Whether you’re using Ping Identity or a custom upstream

kong – 2 services same route

In Kong Gateway, you cannot have two services bound to the exact same route — a route must be unique in terms of its combination of matching rules (such as paths, hosts, methods, etc.).


Why You Can’t Have Duplicate Routes

Kong uses the route’s matching criteria to determine which service should handle a request. If two routes have the same matching rules, Kong can’t disambiguate, which leads to a conflict error when trying to create the second route.

For example:

# Service A
curl -i -X POST http://localhost:8001/services/ --data name=service-a --data url=http://api-a
curl -i -X POST http://localhost:8001/routes --data name=route-a --data service.name=service-a --data paths[]=/api

# Service B
curl -i -X POST http://localhost:8001/services/ --data name=service-b --data url=http://api-b
curl -i -X POST http://localhost:8001/routes --data name=route-b --data service.name=service-b --data paths[]=/api

The second POST /routes will fail with:

HTTP 409 Conflict – duplicate entry


Workarounds / Alternatives

GoalSolution
Blue/Green or Canary DeploymentsUse Kong Plugins (e.g., traffic-split, canary) or upstreams and targets instead of duplicate routes.
Different consumers/users hitting different backendsUse request transformers, ACLs, or Kong Enterprise Route-by-header/Route-by-consumer plugins.
Same path, different method or hostYou can differentiate routes by methods[], hosts[], or headers.

🧪 Example: Two Routes with Same Path, Different Hosts

# Route 1
curl -i -X POST http://localhost:8001/routes \
  --data name=api-v1 \
  --data paths[]=/api \
  --data hosts[]=v1.example.com \
  --data service.name=service-a

# Route 2
curl -i -X POST http://localhost:8001/routes \
  --data name=api-v2 \
  --data paths[]=/api \
  --data hosts[]=v2.example.com \
  --data service.name=service-b

These can coexist because their hosts[] fields are different.


Summary

Route Matching RuleMust Be Unique For
paths[]Same host/methods/headers
hosts[]If combined with same path
methods[], headersCan disambiguate routes with same path