langwatch/clickhouse-serverless) can carry
extra ClickHouse users next to the default user LangWatch itself uses. Use
them for BI tools, reporting jobs, CI pipelines and engineers who query traces
directly. Each user gets one tier, and logs in with either a rolling
password or an OIDC token. The feature is off until you give the image an
access file.
Set your own password for the
default user. In Docker Compose, put
CLICKHOUSE_PASSWORD in .env (for example openssl rand -hex 24). Without it
the compose file falls back to the published langwatch, which the server warns
about at every boot; the next major release removes that fallback.Tiers
With an access file, the server defines four roles, each with a settings profile of the same name. Without one, none of them exists. To use the tiers for users you write yourself, setCLICKHOUSE_ACCESS_TIERS=true.
READ_TIER_MAX_EXECUTION_TIME sets the execution-time cap of the inspect and
read tiers, in seconds (default 300). A read user cannot raise it. By default only admin
users can read system.query_log and the other system tables that hold query
text; a user’s own grants can add a named one.
The access file
The access file lists issuers (for token logins) and users. The image checks it strictly at startup. An unknown key, tier or issuer, or a missing password directory, stops the container with an error that names the problem.access.yaml
ClickHouse applies a profile’s own values without checking its constraints,
so the image checks them. A setting ClickHouse does not know, or a value it
cannot parse, stops the file loading. A user whose settings pass a cap of its
tier, set a capped setting to 0 (no limit), or change a pinned setting is left
out with a warning until the file is fixed. Read users may set
readonly only
to 1 or 2.
A quota limit must be above 0, which ClickHouse reads as no limit. ClickHouse
counts only queries that read data against a quota’s queries limit, so
SELECT 1 does not use it up.
Do not also define an access user in your own users.d files.
Policy
The image checks each user’ssettings, quota and grants against default
rules. A policy block adds to them or replaces them for your install. Each
list takes add, replace, or both. A replaced list starts empty, then takes
the added names.
access.yaml
protected_settings takes effect at the next
restart; the rest apply at the next sync.
Rolling passwords
Arolling login points at a directory. Every regular, non-hidden file in it is
a valid password of at least 16 characters, with at most 8 files per directory.
Give each user its own directory. In Kubernetes, that is one Secret per user.
To rotate a password without downtime:
1
Add the new password
Add a key to the Secret (or a file to the directory) with the new password.
Both passwords now work.
2
Move the client
Give the new password to the client and confirm that it connects.
3
Remove the old password
Delete the old key. To end it at a fixed time instead, add a key
<old-key>.valid_until that holds an RFC 3339 instant, such as
2026-11-30T00:00:00Z.Token logins
A token user logs in with an OIDC JWT (an ID token or a workload token) as its password, over HTTP or the native protocol. A sidecar in the ClickHouse pod accepts the token only when all of these are true:- An asymmetric key of the user’s issuer signed it (RS, PS, ES or EdDSA).
- Its
issequals the issuer’surl, and itsaudcontains the audience. - Its
expis in the future. There is no leeway: the token stops working at that second. Itsnbfgets 30 seconds of clock leeway. - Its
username_claimequals the user’ssubject. - Every
required_claimsentry matches.
Kubernetes workloads
A pod can log in with a projected ServiceAccount token. Mount one with the audienceclickhouse in the client pod:
jwks_url at the API server, and give the cluster CA as
ca_file through access.extraFiles:
system:service-account-issuer-discovery ClusterRole to the group
system:unauthenticated.
GitHub Actions
A workflow can log in with its OIDC token. Give the jobid-token: write, and
request a token with the audience clickhouse:
People, through your identity provider
Engineers can log in with an ID token from your company’s identity provider. Use the OAuth client ID of the application that issues the tokens as the audience, match on a verified email, and give each person their own user:Dynamic-only mode
Dynamic-only mode removes every long-lived password from ClickHouse. People and workloads log in with short-lived OIDC tokens only. A password leaked from a Secret, Terraform state, a backup or a laptop is then of no use, because there is none, and a leaked token expires within minutes. Turn it on withmode: dynamic-only at the top of the access file. Under Helm,
set clickhouse.access.dynamicOnly.enabled: true instead. LangWatchQL’s
ClickHouse user still logs in with a password, so under the langwatch chart
the mode also needs clickhouse.lwqlAccess.secretName: "", which leaves
LangWatchQL unavailable on that server:
- refuses to start with
CLICKHOUSE_PASSWORD, a rolling user, or any other file-defined user with a password, and names each one; - locks
default: no address may log in as it; - refuses
CREATE USER ... IDENTIFIED BY, and logs any SQL user that still has a password; - generates a
local_adminpassword at every start, valid only from inside the pod, for initialisation scripts and in-pod tools.
expirationSeconds: 600 works; the kubelet renews the file before
it expires. Read the token file for each connection or request, and never
reuse a token after it expires.
What it does not protect against: an attacker inside the ClickHouse pod; anyone
who can mint tokens for a mapped subject (the issuer’s key, or creating
ServiceAccount tokens or pods in Kubernetes); and the cluster secret, which
replicas share and which still works for anyone who reaches port 9000. Rotate
the cluster secret by changing it and restarting every replica together.
LangWatch itself connects with a password today. Run dynamic-only mode for
separate tools, or wait for the app to support token logins.
Enabling access
Helm
Under thelangwatch chart, set clickhouse.access. (On the standalone
clickhouse-serverless chart, drop the clickhouse. prefix.)
access.yaml and set clickhouse.access.existingConfigMap.
Docker
Mount a directory holding the access file and the password directories, and setCLICKHOUSE_ACCESS_FILE. Mounted at /etc/clickhouse-access, the paths in the
example above work unchanged: put the passwords in
access/secrets/dashboards-passwords/.
Limits
- Sidecar outages. While the sidecar is down, token logins fail. A password
past its
valid_untilkeeps working until the sidecar returns. Removing the password file has the same delay. The chart restarts the sidecar when its health check fails. - Existing sessions. Removing a password or a user stops new logins. It does not end queries already running.
- Clients. The image’s
clickhouse-clientand any HTTP client accept a token as the password. Some drivers limit the password length; check yours with a real token.