DEV Community

Cover image for Your Kafka Schema Registry is wide open
Stéphane Derosiaux for Conduktor

Posted on

Your Kafka Schema Registry is wide open

Quick question about your Kafka setup: right now, which applications are allowed to change or delete which schemas?

Sometimes, it's everyone (because the Schema Registry (SR) is not protected). Sometimes, it's an nginx/traefik in front of their SR to blacklist some routes (like global compatibility) and call it done. Sometimes, it's just to add basic authentication at least. Rarely, it's about authorization.

Authorization is about "what are you allowed to change/break?"

Let me show you where the gap actually is, because "just put a proxy in front of it" is not enough.

Authentication isn't authorization

A schema registry exists to solve a coordination problem. Producers and consumers ship on their own schedules, so they need a shared, versioned contract for the shape of each message. Producers register a schema, consumers resolve it by ID, and the registry enforces compatibility as things evolve so one side's change doesn't blow up the other.

That makes it a very high-value target. Everything producing or consuming structured data depends on it. So "who can change it" should be a first-class question and in the free Confluent Schema Registry, the answer is "anyone."

The default listener is plain HTTP:

# Schema Registry default — plaintext, every interface
listeners=http://0.0.0.0:8081
Enter fullscreen mode Exit fullscreen mode

Per-subject access control isn't in the free version. It's a commercial add-on:

"Until either ACLs or Role-Based Access Control is also enabled for Schema Registry, any user can create, alter, and delete Schema Registry subjects."

Create/alter/delete arê the controls you actually want is per-subject: the payments team can write `payments-` schemas and nothing else.*

It's not just Confluent

The free registry is the most obvious offender, but it's not alone. Every option handles per-subject authorization differently, and most of it is off by default:

Approach Per-subject authz Default Uses your Kafka identity
Confluent SR (free) none open, plain HTTP no
Apicurio registry-wide roles only off no
Karapace yes, regex ACL per subject off no
Confluent RBAC / plugin yes off, commercial Confluent's plane
Generic HTTP proxy coarse, path-prefix only you build it no — matches the URL

Per-subject control exists in a couple of places, but it's either a hand-edited auth file (Karapace) or a paid platform tier (Confluent RBAC). None of the free or open-source options tie the rule to the Kafka identities you already manage, or give you an audit trail that lines up with Kafka.

Why a generic HTTP proxy is a bad solution

Since the registry speaks HTTP, the natural thinking is to set up an nginx or an API gateway and only allow the routes you want. For basic guardrails on a single registry, that's cheap and reasonable. Subject names even show up in the path, so you can gate writes by prefix:

# Allow writes only to payments-* subjects
location ~ ^/subjects/payments-.*/versions {
    proxy_pass http://schema-registry:8081;
}
Enter fullscreen mode Exit fullscreen mode

Looks fine. Then you need to maintain the nginx file, meet the edge cases, and you can only reason about URLs: not schemas, not identities. Here's the one that always gets people:

GET /schemas/ids/42
Enter fullscreen mode Exit fullscreen mode

That fetches a schema by numeric ID. There's no subject in the path to match on, so your careful payments-* rule doesn't apply — and that call can return any schema, including another team's.

  • It authorizes the network path, not your Kafka principal: so it's only as strong as the firewall around port 8081.
  • It assumes subjects are named after topics. Switch to RecordNameStrategy and the subject is a record name, so your prefix rules stop lining up.
  • It can't tell a deliberate registration from a client silently auto-registering on first produce:
# One flag away from clients registering schemas you never reviewed
auto.register.schemas=true
Enter fullscreen mode Exit fullscreen mode

Try to go down this path will create an abomination you'll need to maintain forever with your own model of subjects and owners inside your proxy. That's a lot of infrastructure to own just to answer "who can touch payments schemas."

What is "closed by default"?

Per-subject authorization should be:

  1. By subject, prefix, and wildcard, not by URL path that happens to contain a subject sometimes.
  2. Tied to the Kafka identities you already use, the same principals you manage for topic ACLs, not a second, parallel access system.
  3. Logged end to end, every operation and every denial, in a trail that lines up with the rest of your Kafka audit.

The way to get all three without a platform license or bespoke plumbing is a schema-aware proxy, something that understands subjects and requests rather than URLs. That's the category Conduktor's Schema Registry Proxy sits in: it fronts the registry you already run, checks read and write permissions per subject, logs every call, and doesn't need any producer or consumer changes. You just point schema.registry.url at the proxy and keep your current registry, Confluent or open source:

# Clients don't change — they just talk to the proxy
schema.registry.url=http://schema-registry-proxy:8081
Enter fullscreen mode Exit fullscreen mode

Now you have a protected schema registry, reads and writes, that can even be linked to a self-service framework where ownership is a first-class citizen.

Top comments (0)