The Problem With How Most Teams Run Kong
If you set up Kong the default way, everything lives together — routing, policy enforcement, plugin execution, live traffic handling. One deployment doing all the things.
It works. Until it doesn't.
When traffic spikes, you scale up. But you're scaling the control plane too, which barely does anything at runtime. You're paying compute for config management that gets touched only when something changes — not on every request.
That was us. Scaling more than we needed to, paying for it, and not realizing why.
Splitting Control Plane from Data Plane
The data plane is hot. It handles every live request, every millisecond, 24/7. It needs to be fast, lean, and close to your services.
The control plane is cold. It pushes config — route definitions, plugin settings, policy changes. It fires when something changes, then sits quiet.
When you separate them:
- Data plane scales with your actual traffic
- Control plane runs small and cheap, sized for config ops not request volume
- You stop paying for compute you're not using
That architectural change alone dropped our gateway infra cost by 34%. No feature removal. No degraded performance. Just stop running one thing at the scale of another.
Then We Added Plugins — And Kong Became Something Else
This is where it gets interesting. Once the infra is clean, you can actually think about what Kong should be doing for your stack.
JWT Validation at the Gateway
Every request carries a token. Kong verifies it before the request gets anywhere near a service. No valid token, request dies at the edge.
Your services stop writing auth logic entirely. No more 12 slightly different JWT implementations across 12 services. One place, one standard, enforced consistently.
plugins:
- name: jwt
config:
secret_is_base64: false
claims_to_verify:
- exp
OAuth 2.0 for Third-Party Integrations
Handled at the gateway, not scattered across services. External partners authenticate once at the edge. Your internal services never see unauthenticated traffic.
Rate Limiting Per Consumer, Not Just Per Route
This is the one most teams miss. Route-level rate limiting is blunt. Consumer-level rate limiting is precise.
plugins:
- name: rate-limiting
consumer: free-tier
config:
minute: 100
- name: rate-limiting
consumer: enterprise
config:
minute: 10000
Same plugin, same gateway, different policy per JWT claim. Free tier gets 100 req/min. Enterprise gets 10,000. Zero application code involved.
Request Transformation
Strip headers you don't want passing through to services. Inject headers your services expect. Normalize payloads from external partners sending data in formats your team didn't design for — all before the request touches your backend.
IP Whitelisting on Internal Routes
Certain paths accessible only from known sources. One config block. Applies across the entire stack.
What This Actually Changed
Before: auth logic lived in every service. Every team implemented it differently. Every security audit found inconsistencies. Every new service started from scratch building things that had already been built six times.
After: the gateway owns identity, rate policy, request shape, and access control. Services own business logic. That boundary is clean and it stays clean.
When we did a security audit post-migration, the findings dropped significantly. Not because we wrote better application code — we hadn't touched it. Because we moved the security surface to one place and made it consistent.
The Architecture That Came Out of This
External Traffic
│
▼
[Kong Data Plane] ◄──── [Kong Control Plane] (small, separate, cheap)
│ │
JWT auth Config push
Rate limiting Plugin management
Request transform Route definitions
IP whitelist
│
▼
[Your Services] ←── Business logic only
The data plane is the only thing in the hot path. The control plane is a config server. Your services are finally just services.
TL;DR
- Split control plane from data plane → stop scaling what doesn't need to scale
- JWT at the gateway → services never handle auth again
- Per-consumer rate limiting → fine-grained control without application changes
- Request transformation → normalize at the edge, not inside your code
- One security surface → consistent, auditable, maintainable
If you're running Kong as a glorified reverse proxy, you're leaving most of its value on the table.
Top comments (0)