klens

Configuration

Every key klens reads from config.yaml, with its type, default, and limits.

klens reads one YAML file at startup. It loads config.yaml from its working directory, or the file that the KLENS_CONFIG_PATH environment variable names. klens reads no other environment variable of its own. A secret can name an environment variable with {env: NAME}.

Every key is optional unless this page marks it as required. An omitted key takes its default. An unknown key stops startup, and so does a value klens cannot read. The error names the line and the column, for example must be at least 1s at line 12, column 15. klens reads the file once, so a change takes effect at the next start.

config/clusters.example.yaml holds every key with its default.

Value types

TypeFormatExample
DurationA number and a unit, or ISO 8601250ms, 10s, 1h 30m, PT10S
Socket addressAn IP address and a port0.0.0.0:8080, "[::1]:8080"
SecretA map with exactly one key, value, env, or file{env: KAFKA_PASSWORD}
PrivilegeA privilege name in snake caserecords, create_topics

Secrets

A secret names where klens reads it.

FormReads
{value: TEXT}The text as written. Quote a value that YAML would read as a number.
{env: NAME}The environment variable NAME. Startup fails when it is unset.
{file: PATH}The file at PATH, without its trailing newline. Startup fails when the file cannot be read.

A plain string where a secret belongs stops startup, and the error does not repeat the string. Some secrets are key material and must be at least 32 bytes: mcp.secret and obfuscation.secret.

Top level

KeyTypeDefaultDescription
bindSocket address0.0.0.0:8080The address of the UI, /api, /health, and /ready.
allowed_hostsList of hosts[localhost, 127.0.0.1, "::1"]The hosts klens answers while auth is off. See allowed hosts.
log_leveloff, error, warn, info, debug, or traceinfoThe level of the log klens writes to standard output.
clustersMap of clusters{}The Kafka clusters, by name. The UI lists them in file order.
authAuthNoneOIDC sign-in and roles. Without it, the UI and /api are open.
mcpMCPNoneThe MCP server for AI agents. Without it, klens serves no /mcp.
tuningTuningSee tuningTimeouts, pool sizes, limits, and polling periods for every cluster.

allowed_hosts

While auth is off, klens answers only a request whose Host header names an entry in this list. Any other request gets 403 HOST_NOT_ALLOWED, and so does a request without a host. With auth, klens ignores the list. /health and /ready answer every host. /mcp ignores the list.

An entry is a host name or an IP address, with an optional port.

  • An entry without a port matches the host on any port. An entry with a port matches that port only.
  • Names match in any case.
  • An IPv6 address takes brackets when a port follows. YAML needs quotes around such an entry, as in "[::1]:8080".

These values stop startup:

  • An empty list.
  • An entry with a scheme, a path, or a user, such as https://klens.example.com.
  • An entry with a wildcard, such as *.example.com.
  • A port that is not a number from 0 to 65535.
  • An IPv4 address in a short form, such as 10.1.

Clusters

Each key under clusters is a cluster name. A name keeps its case and appears once.

KeyTypeDefaultDescription
bootstrap_serversList of host:portRequiredThe brokers klens connects to first.
client_idStringklens-<cluster name>The client ID klens sends to the brokers.
writableBooleanfalseWhether klens may change this cluster. A change also needs its privilege.
tlsTLSNoneConnect over TLS. An empty block, tls: {}, turns TLS on.
saslSASLNoneAuthenticate with SASL.
schema_registrySchema RegistryNoneThe registry that decodes and encodes framed payloads.
obfuscationObfuscationNoneRules that hide parts of records.

tls

KeyTypeDefaultDescription
ca_certPathNoneA PEM file of the CAs to trust. Without it, klens trusts the Mozilla root CAs it ships with.
client.certPathNoneA PEM client certificate for mutual TLS. Requires client.key.
client.keyPathNoneThe PEM private key of client.cert. Requires client.cert.
insecure_skip_verifyBooleanfalseSkip the check of the broker certificate.

sasl

KeyTypeDefaultDescription
mechanismPLAIN, SCRAM-SHA-256, or SCRAM-SHA-512RequiredThe SASL mechanism.
usernameStringRequiredThe Kafka user.
passwordSecretRequiredThe password of the Kafka user.

SASL runs over TLS when the cluster also has a tls block, and over plaintext otherwise.

schema_registry

klens reads a Confluent-compatible Schema Registry API.

KeyTypeDefaultDescription
urlURLRequiredThe base URL of the registry.
auth.usernameStringRequired in authThe basic auth user.
auth.passwordSecretRequired in authThe basic auth password.

Credentials travel over http:// only to a loopback host. A remote registry with auth must use https://.

obfuscation

KeyTypeDefaultDescription
secretSecret, at least 32 bytesRequiredThe key of the hash strategy, used as written.
rulesList of rulesRequiredThe rules. No topic may match two rules.

Obfuscation rules

KeyTypeDefaultDescription
topicsList of topic patterns[]The topics the rule covers. A pattern is an exact name, or a prefix that ends in *.
fieldsList of {path, strategy}[]Fields of a value that the schema registry decoded, by dotted path, such as card.number.
patternsList of {regex, strategy}[]Regular expressions that run on the text of the key and the value.
keyStrategyNoneA strategy for the whole key.
valueStrategyNoneA strategy for the whole value.
headersList of strings[]The names of headers whose values klens masks.
unparsedmask or allowmaskWhat fields do to a value that did not decode. mask masks the whole value. allow shows it as it is.

The strategies are these:

StrategyResult
mask***
hashA token such as kx:3f9a2c481b7d6e05. Equal values give equal tokens.
dropA field disappears. A pattern match is deleted.

A path that meets an array applies the rest of the path to each element, so items.sku covers the sku of every element. * may appear only at the end of a topic pattern. Two patterns that can match the same topic stop startup with topics '<a>' and '<b>' overlap. About obfuscation explains how the rules apply.

Auth

The auth block turns on sign-in with OpenID Connect.

KeyTypeDefaultDescription
oidc.issuerURLRequiredThe issuer URL. klens compares it to the provider's issuer byte for byte.
oidc.client_idStringRequiredThe OIDC client ID.
oidc.client_secretSecretRequiredThe OIDC client secret.
oidc.redirect_uriURLRequiredThe callback URL, <klens URL>/api/auth/callback. Session cookies are Secure when it uses https.
oidc.scopesList of strings[openid, email, profile]The scopes klens requests.
oidc.groups_claimStringgroupsThe ID token claim that lists the groups of a user.
session.login_timeoutDuration10mHow long a sign-in may stay at the provider.
session.max_ageDuration12hThe longest a session lasts. A session also ends when its ID token expires.
rolesMap of rolesNoneThe roles, by name. Without roles, every signed-in user holds every privilege.

Roles

KeyTypeDefaultDescription
privilegesList of privilegesRequiredThe privileges the role grants beyond the catalog. An empty list grants the catalog only.
bindingsList of bindingsRequiredWho holds the role, and where.
bindings[].groupsList of stringsRequiredThe groups, from oidc.groups_claim, that hold the role.
bindings[].clustersList of cluster namesEvery clusterThe clusters where the binding applies.

With roles, a user whose groups match no binding cannot sign in.

MCP

The mcp block turns on the MCP server at /mcp.

KeyTypeDefaultDescription
bindSocket addressRequiredThe address of /mcp. It must differ from the top-level bind, and it serves nothing but /mcp.
secretSecret, at least 32 bytesNoneThe shared secret a gateway sends as Authorization: Bearer. Required with auth.
privilegesList of privileges[records, topic_configs, broker_configs, schema_text, acls]The ceiling every MCP call holds.
clustersList of cluster namesEvery clusterThe clusters MCP reaches. An empty list reaches none.

privileges takes only records, topic_configs, broker_configs, schema_text, acls, create_topics, produce, and register_schemas. Any other privilege stops startup. These rules also stop startup:

  • mcp.bind equals bind.
  • mcp.clusters names a cluster that clusters does not configure.
  • auth is set and mcp.secret is not.

klens logs a warning at startup in these cases:

  • mcp.secret is unset and privileges names a write.
  • privileges names records or schema_text beside a write.

Tuning

Every key under tuning applies to every cluster. This block shows the defaults.

config.yaml
tuning:
  kafka:
    connect_timeout: 10s
    request_timeout: 10s
    consume_timeout: 5s
    max_in_flight_requests: 32
    max_response_mib: 32
  schema_registry:
    timeout: 5s
    subject_fetch_concurrency: 8
    missing_schema_ttl: 60s
  scan:
    pool_per_topic: 2
    pool_total: 16
    pool_idle_ttl: 60s
    poll_wait: 100ms
  records:
    max_limit: 500
    min_window: 4
    window_multiplier: 2
    search_window_multiplier: 8
  tail:
    batch_limit: 100
    interval: 250ms
    poll_wait: 500ms
    max_live: 32
  ingest:
    topology: 10s
    high_watermark: 3s
    low_watermark: 30s
    config: 60s
    subjects: 30s
    log_dirs: 60s
    acls: 60s
    quotas: 60s
    scram_users: 60s
    offset_tick: 1s
    fast_offset: 2s
    slow_offset: 20s
    offset_fetch_concurrency: 32
    interest_ttl: 30s
    idle_heartbeat: 15s
    max_sample_gap: 15s
  mcp:
    max_concurrent_calls: 16
    live_calls_per_minute: 30

A count must be at least 1, except records.min_window, records.window_multiplier, records.search_window_multiplier, and tail.max_live, which may be 0.

tuning.kafka

KeyDefaultDescription
connect_timeout10sHow long klens waits to open a broker connection.
request_timeout10sHow long klens waits for a broker response. klens raises it to connect_timeout when it is smaller.
consume_timeout5sHow long one record page or the start of one live tail may read.
max_in_flight_requests32The most requests in flight on one broker connection.
max_response_mib32The largest broker response frame, in MiB.

tuning.schema_registry

KeyDefaultDescription
timeout5sHow long klens waits for a registry response.
subject_fetch_concurrency8The most subjects klens reads from the registry at once.
missing_schema_ttl60sHow long klens remembers that the registry does not know a schema ID.

tuning.scan

KeyDefaultDescription
pool_per_topic2The most idle record readers klens keeps for one topic.
pool_total16The most idle record readers klens keeps across all topics.
pool_idle_ttl60sHow long an idle record reader stays open. At least 1s.
poll_wait100msThe longest one poll of a record page waits for data.

tuning.records

KeyDefaultDescription
max_limit500The most records one page may ask for.
min_window4The fewest offsets klens reads from each partition for one page.
window_multiplier2For one page, klens reads the page limit times this number of offsets from each partition.
search_window_multiplier8The multiplier in place of window_multiplier while a contains or schemaId filter runs.

tuning.tail

KeyDefaultDescription
batch_limit100The most records in one live tail frame.
interval250msThe least time between two frames of a live tail.
poll_wait500msThe longest one poll of a live tail waits for data.
max_live32The most live tails served at once, across every cluster. Past it, a new tail gets 503 TOO_MANY_TAILS.

tuning.ingest

klens keeps a projection of each cluster in memory and refreshes it in the background, one lane per kind of data. These keys set how often each lane reads Kafka or the registry. Each period must be at least 1s. How klens reads Kafka explains the lanes.

KeyDefaultDescription
topology10sBrokers, topics, partitions, and consumer groups.
high_watermark3sThe end offset of each partition. Produce rates come from it.
low_watermark30sThe start offset of each partition.
config60sTopic and broker configs.
subjects30sSchema subjects and the schema IDs they use.
log_dirs60sLog dirs and sizes. klens also reads them when a topic or a broker appears.
acls60sACL bindings.
quotas60sClient quotas.
scram_users60sSCRAM credentials.
offset_tick1sHow often the offset lane checks which groups are due.
fast_offset2sHow often klens reads the offsets of a group that someone looks at.
slow_offset20sHow often klens reads the offsets of every other group.
offset_fetch_concurrency32The most groups whose offsets klens reads at once.
interest_ttl30sHow long a group stays on fast_offset after someone looks at it.
idle_heartbeat15sHow long a topic stays quiet before its produce rate drops to zero.
max_sample_gap15sWatermark samples older than this do not count toward a rate.

tuning.mcp

KeyDefaultDescription
max_concurrent_calls16The most MCP tool calls served at once, across every client. Past it, a call fails with RATE_LIMITED.
live_calls_per_minute30The most calls a minute to the MCP tools that read Kafka live or change it, shared by every client. Past it, a call fails with RATE_LIMITED.

On this page