Tenant isolation at the protocol layer.
Topic names, consumer group IDs, and transactional IDs are namespaced
per tenant on the wire. Two tenants can both publish to orders
without ever seeing each other's partitions or offsets.
Klamm sits between your clients and your Apache Kafka cluster. Each tenant connects with their own credentials and sees their own topics, consumer groups, and transactions. None of them see each other.
01 · why
Kafka has no native notion of a tenant. Teams that need one usually implement it in one of three places — application code, the broker fleet, or the client SDK. Klamm puts it on the wire.
02 · capability
Four properties that fall out of doing isolation at the protocol layer rather than above it.
Topic names, consumer group IDs, and transactional IDs are namespaced
per tenant on the wire. Two tenants can both publish to orders
without ever seeing each other's partitions or offsets.
Any client that speaks SASL/PLAIN, SCRAM-SHA-256, or SCRAM-SHA-512 connects to Klamm the same way it connects to Kafka. Tenant identity is carried by the SASL credential; no SDK changes are required.
A single binary and a single YAML file. Point tenants at Klamm's
bootstrap address instead of the broker's. Klamm handles upstream
broker discovery, broker route generation, and protocol rewriting.
SIGHUP reloads tenant changes without dropping
connections.
Dynamic namespaces for quick onboarding, or explicit allow-lists for strict environments. Per-tenant limits on connections and in-flight requests. Topic deletion is a separate permission, disabled by default.
03 · behaviour
A tenant's credentials select a namespace. Klamm translates every identifier that crosses the boundary — in both directions — so each side of the proxy operates in the vocabulary it expects.
orders __vt_acme_orders payments-svc __vt_acme_payments-svc orders-producer-1 __vt_acme_orders-producer-1 proxy.example.com:9093 broker-1.kafka.internal:9092 orders (in payload) __vt_acme_orders (in payload) 04 · surface
Klamm reads a single configuration file and negotiates everything else from the cluster. Upstream broker IDs, partition leaders, API versions, and SASL mechanisms are discovered at runtime; route ports are derived deterministically from the broker port range.
Tenant and credential changes reload on SIGHUP. Topology changes
require a restart — by design.
proxy:
listener_sets:
- name: plaintext
port_range:
bind_host: "0.0.0.0"
advertised_host: "proxy.example.com"
bootstrap_port: 9092
broker_port_range: { start: 9093, end: 9095 }
broker_id_base: 1
upstream:
bootstrap:
- "kafka-1.internal:9092"
- "kafka-2.internal:9092"
- "kafka-3.internal:9092"
tenants:
- name: acme
allowed_topics: [orders, billing, events, audit.log]
auth:
credentials:
- username: acme
password_file: "secrets/acme.password"
- name: globex
allowed_topics: [orders, users]
auth:
credentials:
- username: globex
password_file: "secrets/globex.password" 05 · coverage
Klamm implements the Kafka APIs a tenant uses: produce, fetch, groups, transactions, admin, auth. Versions are intersected with the upstream broker's advertised range at connection time. Production readiness is tracked separately; see status.
Produce v3–12Fetch v4–18ListOffsets v1–9OffsetForLeaderEpoch v3–4Metadata v0–13DescribeCluster v0–2DescribeTopicPartitions v0FindCoordinator v0–6JoinGroup v0–9SyncGroup v0–5Heartbeat v0–4ConsumerGroupHeartbeat v0–1InitProducerId v0–5AddPartitionsToTxn v0–5EndTxn v0–5TxnOffsetCommit v0–5CreateTopics v2–7DeleteTopics v1–6DescribeConfigs v1–4ACL admin (opt-in)SaslHandshake v0–1SaslAuthenticate v0–2ApiVersions v0–406 · compatibility
Each of the clients below ships a substantial integration test suite. Klamm runs it with the proxy in the path.
go test -timeout 5m ./... upstream root fixture go test ./... · -tags=unsafe 2.7.0 · 2.8.1 · 3.7.0 make test 4.0.0 · 3.9.0 · 2.8.2 · PLAIN / SCRAM-256 / SCRAM-512 run-test.sh -Q -E -L trivup KafkaCluster fixtures jest broker group 2.4 (three-broker compose) 07 · status
Klamm is pre-release. OAUTHBEARER and GSSAPI are not implemented. Upstream TLS is server-auth only. KIP-848 regex subscriptions are deferred. Connection pooling is deferred. Per-pod limits are not distributed across proxy instances. Each of these gaps is documented on its own page.
The quickstart brings up Kafka, Klamm, and two tenant consoles with one
docker compose command.