Documentation · Configuration

Configuration examples

Four configurations covering common deployments — single broker, three-broker cluster, upstream TLS, and SNI-routed downstream TLS.

Klamm reads a single YAML file passed via --config. Relative paths inside it — password_file, cert_file, key_file, ca_file — resolve against the config file’s directory.

Single broker

# proxy.yaml
proxy:
  listener_sets:
    - name: plaintext
      port_range:
        bind_host: "127.0.0.1"
        advertised_host: "127.0.0.1"
        bootstrap_port: 29092
        broker_port_range:
          start: 29093
          end: 29093
        broker_id_base: 1
admin:
  bind: "127.0.0.1:28080"
upstream:
  bootstrap:
    - "127.0.0.1:9092"
tenants:
  - name: tenant-a
    auth:
      credentials:
        - username: tenant-a
          password_file: "secrets/tenant-a.password"

Run it with the published image, mounting the config directory:

docker run --rm --network host \
  -v "$PWD:/etc/klamm:ro" -w /etc/klamm \
  jerrinot/klamm:snapshot --config /etc/klamm/proxy.yaml

--network host keeps 127.0.0.1:9092 reachable on Linux. On Docker Desktop replace it with published ports (-p 29092:29092 -p 28080:28080) and point upstream.bootstrap at host.docker.internal:9092.

Clients connect to 127.0.0.1:29092 using SASL/PLAIN with username=tenant-a. SCRAM-SHA-256 and SCRAM-SHA-512 use the same tenant credential material when clients prefer SCRAM. This example omits allowed_topics, so it uses dynamic namespace mode: producing to a new logical topic creates or uses the tenant-prefixed physical topic upstream when the broker allows topic auto-creation.

Listener-set-bound tenant (no downstream SASL)

For compatibility testing or trusted local fixtures, a listener set can skip downstream SASL and bind every connection on that listener set to one tenant:

proxy:
  listener_sets:
    - name: local-no-auth
      auth:
        mode: none
        tenant: tenant-a
      port_range:
        bind_host: "127.0.0.1"
        advertised_host: "127.0.0.1"
        bootstrap_port: 29092
        broker_port_range:
          start: 29093
          end: 29093
        broker_id_base: 1

This does not disable tenant isolation or topic/group/transactional-id rewriting. It only replaces per-connection SASL identity with listener-set-scoped tenant identity; sessions are recorded as user anonymous.

Three-broker cluster

Expose one bootstrap route and a deterministic broker port range. Broker IDs are discovered from upstream Metadata. The example maps broker 1 to port 29093, broker 2 to 29094, and broker 3 to 29095.

proxy:
  listener_sets:
    - name: plaintext
      port_range:
        bind_host: "0.0.0.0"
        advertised_host: "proxy.example.com"
        bootstrap_port: 29092
        broker_port_range:
          start: 29093
          end: 29095
        broker_id_base: 1
admin:
  bind: "0.0.0.0:28080"
upstream:
  bootstrap:
    - "kafka1:9092"
    - "kafka2:9092"
    - "kafka3:9092"
tenants:
  - name: team-payments
    auth:
      credentials:
        - username: payments-prod
          password_file: "secrets/payments.password"
    allowed_topics:
      - transactions
      - settlements
  - name: team-analytics
    auth:
      credentials:
        - username: analytics-prod
          password_file: "secrets/analytics.password"
    allowed_topics:
      - transactions
      - page-views

Both tenants can access transactions, but each sees only their own consumer groups. team-payments cannot see page-views; team-analytics cannot see settlements.

Upstream TLS

Set upstream.tls.ca_file when brokers require TLS:

upstream:
  tls:
    ca_file: "certs/upstream-ca.pem"
  bootstrap:
    - "broker-1.kafka.example.com:9093"
    - "broker-2.kafka.example.com:9093"

The proxy verifies broker certificates against the configured CA bundle. TLS SNI and certificate server-name verification use the host part of each upstream address discovered from the bootstrap Metadata path.

TLS with SNI routing

proxy:
  listener_sets:
    - name: tls-sni
      auth:
        mode: required
      tls:
        cert_file: "certs/server.pem"
        key_file: "certs/server-key.pem"
      sni:
        bind: "0.0.0.0:9092"
        bootstrap_host: "bootstrap.kafka.example.com"
        broker_host_template: "broker-{broker_id}.kafka.example.com"

SNI routing lets the bootstrap host and broker hosts share a single TLS port. The proxy routes based on the TLS Server Name Indication field; clients that do not send SNI are rejected for an SNI-routing listener.

DNS must point both the bootstrap host and every generated broker host to the proxy. With the example above, bootstrap.kafka.example.com and names such as broker-1.kafka.example.com must resolve to the proxy address. The downstream TLS certificate must also be valid for those names, either through explicit SANs or a wildcard such as *.kafka.example.com.

Reference Every YAML option accepted by the config loader, with defaults and constraints, is listed in the configuration reference.