Documentation · Configuration
Configuration reference
Every YAML option consumed by the config loader, with defaults and constraints.
The loader accepts one YAML file via --config <path>. Omit optional sections
unless they are needed. Relative password_file, cert_file, key_file, and
ca_file paths resolve against the config file’s directory.
Structure
proxy:
listener_sets:
- name: plaintext
auth:
mode: required
port_range:
bind_host: "0.0.0.0"
advertised_host: "proxy.example.com"
bootstrap_port: 9092
broker_port_range: { start: 9093, end: 9192 }
broker_id_base: 1
- name: tls-sni
auth: { mode: required }
tls:
cert_file: "certs/server.pem"
key_file: "certs/server-key.pem"
sni:
bind: "0.0.0.0:9443"
bootstrap_host: "bootstrap.kafka.example.com"
broker_host_template: "broker-{broker_id}.kafka.example.com"
admin:
bind: "127.0.0.1:28080"
acl_admin:
mode: disabled
control_plane:
discovery:
refresh_interval_ms: 5000
deadline_ms: 1000
stale_grace_period_ms: 300000
probe:
refresh_interval_ms: 5000
deadline_ms: 1000
suspect_backoff_initial_ms: 250
suspect_backoff_max_ms: 5000
suspect_backoff_jitter_ms: 100
healthy_recycle_interval_ms: 300000
authenticated_unbound_timeout_ms: 30000
upstream:
bootstrap:
- "broker-1.kafka.example.com:9092"
- "broker-2.kafka.example.com:9092"
connect_timeout_ms: 5000
max_unauthenticated_upstreams: 64
tls:
ca_file: "certs/upstream-ca.pem"
discovery:
sasl:
mechanism: PLAIN
username: "klamm-discovery"
password_file: "secrets/discovery.password"
tenants:
- name: tenant-a
allowed_topics: [orders]
topic_deletion: { enabled: false }
limits:
max_connections: 100
max_inflight: 500
auth:
credentials:
- username: tenant-a
password_file: "secrets/tenant-a.password"
upstream:
sasl:
mechanism: PLAIN
username: "__vt_tenant-a_tenant-a"
password_file: "secrets/tenant-a-upstream.password"
Core rules
proxy.listener_setsis the public listener model. Each listener set must choose exactly one allocation strategy:port_rangeorsni.proxy.listener_sets[].port_rangecreates one bootstrap listener and a deterministic broker route range. Broker route port isbroker_port_range.start + (broker_id - broker_id_base). Discovered broker IDs outside the configured range are not exposed and protocol rewrites fail closed instead of leaking upstream addresses.proxy.listener_sets[].snicreates one TLS listener whose bootstrap and broker routes are distinguished by TLS Server Name Indication. It requirestlson the same listener set.proxy.listener_sets[].auth.modedefaults torequired.mode: nonerequiresauth.tenantand binds every downstream connection on that listener set to the configured tenant as useranonymous; the tenant must exist. Settingauth.tenantwhilemodeisrequiredis rejected.adminis optional. If present,admin.bindmust be a socket address and must not conflict with a proxy listener bind address.acl_admin.modedefaults todisabled. In this mode Klamm does not advertiseCreateAcls,DescribeAcls, orDeleteAcls, and rejects those requests if a client sends them anyway.acl_admin.mode: broker-delegatedenables ACL Admin API virtualization through the upstream Kafka broker. It requires credential-bound downstream authentication on every listener set, requires every tenant credential to defineupstream.sasl, and requiresupstream.sasl.usernameto equal__vt_{tenant}_{username}so broker runtime authorization uses the same physical principal namespace as ACL Admin API rewrites.upstream.bootstrapmust contain at least one upstream broker bootstrap address. Broker membership and broker IDs are discovered through Kafka Metadata responses; do not list the upstream broker inventory in Klamm config.upstream.tls.ca_fileenables TLS to upstream brokers.proxy.listener_sets[].sni.bootstrap_hostand every generatedbroker_host_templatehostname must resolve to the proxy and be covered by the downstream TLS certificate SANs.control_planecan be omitted; defaults are listed in the control plane table below.tenantscan be omitted or empty, but no downstream credential can authenticate until a matching tenant credential is configured.- Tenant names must use only lowercase ASCII letters, digits, and
-, must be at most 40 characters, and cannot contain_. allowed_topicsomitted means dynamic namespace mode.allowed_topics: []means static deny-all mode. A non-empty list means static allow-list mode.allowed_topics: nullis rejected.- Logical topic names in
allowed_topicsmust be non-empty, must not start with__, and may only use ASCII letters, digits,.,_, and-. Prefixed physical topic names must fit Kafka’s 249-character topic-name limit. topic_deletion.enableddefaults tofalseand must betrueforDeleteTopicsto pass, regardless of topic mode.- Downstream tenant credentials support SASL/PLAIN, SCRAM-SHA-256, and
SCRAM-SHA-512. SCRAM uses
password_fileby default, or the per-mechanism override fields when configured. - Credential-bound upstream SASL is optional unless
acl_admin.mode: broker-delegatedis enabled. upstream.discovery.saslis optional control-plane authentication for Metadata discovery. It is not a tenant impersonation mechanism and is not used for forwarded tenant traffic.SIGHUPreloads tenant and credential changes. Changes to listener sets, admin, ACL Admin mode, control-plane settings, upstream bootstrap, upstream TLS, and upstream connection limits require a restart.
Listener sets
| Option | Default | Notes |
|---|---|---|
proxy.listener_sets[].name | required | Stable listener-set name used in route status and diagnostics. Must be unique. |
proxy.listener_sets[].auth.mode | required | Downstream authentication mode. required uses SASL/PLAIN, SCRAM-SHA-256, or SCRAM-SHA-512. none skips downstream SASL and binds the listener set to auth.tenant. |
proxy.listener_sets[].auth.tenant | unset | Required only for auth.mode: none; rejected for required-auth listener sets. |
proxy.listener_sets[].tls.cert_file | unset | Enables TLS for a downstream listener set. Required for sni listener sets. |
proxy.listener_sets[].tls.key_file | unset | Private key for the downstream TLS listener set. Required for sni listener sets. |
proxy.listener_sets[].port_range.bind_host | unset | Local interface used for both the bootstrap listener and broker route listeners in the port-range set. |
proxy.listener_sets[].port_range.advertised_host | unset | Host advertised to clients for the bootstrap listener and all broker route listeners in the port-range set. |
proxy.listener_sets[].port_range.bootstrap_port | unset | Client-facing bootstrap port for this listener set. Must not overlap the broker route range or other proxy/admin binds. |
proxy.listener_sets[].port_range.broker_port_range.start | unset | First client-facing broker route port. Broker route port is start + (broker_id - broker_id_base). |
proxy.listener_sets[].port_range.broker_port_range.end | unset | Inclusive last client-facing broker route port. Broker IDs beyond this range are intentionally unmapped. |
proxy.listener_sets[].port_range.broker_id_base | 0 | Broker ID mapped to broker_port_range.start. Use 1 for clusters whose broker IDs start at 1. |
proxy.listener_sets[].sni.bind | unset | TLS bind address for SNI routing. Must include host and port. |
proxy.listener_sets[].sni.bootstrap_host | unset | Bootstrap hostname for SNI routing. Must be non-empty, resolve to the proxy, and be covered by the downstream TLS certificate. |
proxy.listener_sets[].sni.broker_host_template | unset | Broker hostname template for SNI routing. Must contain exactly one {broker_id} placeholder; generated names must resolve to the proxy and be covered by the downstream TLS certificate. |
Upstream
| Option | Default | Notes |
|---|---|---|
upstream.bootstrap[] | required | One or more upstream Kafka bootstrap addresses. Klamm discovers broker membership and broker IDs from Metadata. |
upstream.connect_timeout_ms | 5000 | TCP/TLS/SASL upstream connection timeout in milliseconds. Must be greater than zero. |
upstream.max_unauthenticated_upstreams | 64 | Limit for concurrent pre-auth upstream connections used while handling bootstrap ApiVersions. Must be greater than zero. |
upstream.tls.ca_file | unset | CA bundle for server-auth TLS to upstream brokers. |
upstream.discovery.sasl.mechanism | unset | Optional control-plane Metadata discovery SASL mechanism. Supports PLAIN, SCRAM-SHA-256, and SCRAM-SHA-512. |
upstream.discovery.sasl.username | unset | Upstream Kafka username used only by control-plane Metadata discovery. |
upstream.discovery.sasl.password_file | unset | Password file for the control-plane Metadata discovery SASL user. |
Tenants
| Option | Default | Notes |
|---|---|---|
tenants[].limits.max_connections | 100 | Per-tenant downstream connection limit for authenticated sessions. |
tenants[].limits.max_inflight | 500 | Per-tenant maximum in-flight requests per authenticated session. |
tenants[].auth.credentials[].scram_sha256_password_file | unset | Optional SCRAM-SHA-256 password file for this username. Defaults to password_file when unset. |
tenants[].auth.credentials[].scram_sha512_password_file | unset | Optional SCRAM-SHA-512 password file for this username. Defaults to password_file when unset. |
tenants[].auth.credentials[].upstream.sasl.mechanism | unset | Credential-bound upstream SASL. Supports PLAIN, SCRAM-SHA-256, and SCRAM-SHA-512. |
tenants[].auth.credentials[].upstream.sasl.username | unset | Upstream Kafka username used after this downstream credential authenticates. |
tenants[].auth.credentials[].upstream.sasl.password_file | unset | Upstream Kafka password file for the credential-bound SASL user. |
ACL Admin
| Option | Default | Notes |
|---|---|---|
acl_admin.mode | disabled | disabled hides and rejects ACL Admin APIs. broker-delegated enables broker-backed ACL Admin API virtualization and requires required-auth listener sets plus credential-bound upstream SASL usernames matching __vt_{tenant}_{username}. |
Control plane
| Option | Default | Notes |
|---|---|---|
control_plane.discovery.refresh_interval_ms | 5000 | Interval between upstream Metadata discovery refreshes. Must be greater than zero. |
control_plane.discovery.deadline_ms | 1000 | Per-refresh Metadata discovery deadline. Must be greater than zero. |
control_plane.discovery.stale_grace_period_ms | 300000 | Grace period before brokers absent from successful Metadata refreshes are retired. Must be greater than zero. |
control_plane.probe.refresh_interval_ms | 5000 | Interval between upstream broker health probes. Must be greater than zero. |
control_plane.probe.deadline_ms | 1000 | Per-probe deadline. Must be greater than zero. |
control_plane.probe.suspect_backoff_initial_ms | 250 | Initial backoff for suspect brokers. Must be greater than zero. |
control_plane.probe.suspect_backoff_max_ms | 5000 | Maximum suspect-broker backoff. Must be at least suspect_backoff_initial_ms. |
control_plane.probe.suspect_backoff_jitter_ms | 100 | Probe backoff jitter in milliseconds. |
control_plane.probe.healthy_recycle_interval_ms | 300000 | Interval for recycling healthy probe connections. Must be greater than zero. |
control_plane.probe.authenticated_unbound_timeout_ms | 30000 | How long an authenticated downstream session may remain without a bound upstream connection. Must be greater than zero. |