All posts
Configuring ClickHouse® on Kubernetes: Users, Profiles, Quotas, and Secrets

Configuring ClickHouse® on Kubernetes: Users, Profiles, Quotas, and Secrets

May 15, 20265 min readSanjeev Kumar G
Share:

This is the sixth article in our series on running the ClickHouse® database on Kubernetes with the Altinity® Kubernetes Operator. We have a cluster with durable storage. Now we configure the database itself: who can connect, what they are allowed to do, how much they can consume, and how to keep their passwords out of plain text.

The good news is that all of this lives inside the same CHI resource. The operator translates it into the ClickHouse configuration files for you.

The four configuration blocks

Under spec.configuration the operator understands four blocks that map directly to ClickHouse concepts. The users block defines accounts and what they can access. The profiles block defines reusable bundles of settings, such as memory limits, that you attach to users. The quotas block limits how much a user can consume over a time window. The settings block holds server-wide settings. Let us build each one.

Creating a user

A user needs a password and a rule for where it may connect from. Storing a plain password works but is poor practice; instead store a SHA-256 hash. Compute one on your machine:

echo -n 'StrongPassw0rd' | sha256sum

That prints a 64-character hex string. Put it in the CHI as the user's password_sha256_hex, and restrict the networks the user may connect from:

spec:
  configuration:
    users:
      analyst/password_sha256_hex: 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
      analyst/networks/ip:
        - 0.0.0.0/0
      analyst/profile: limited
      analyst/quota: standard

This creates an analyst user authenticated by the hash, reachable from any address (tighten this in production), assigned the limited profile and the standard quota that we define next. Notice ClickHouse never sees the plain password; only the hash lives in the manifest.

Profiles: bundles of settings for users

A profile is a named group of settings you attach to users. A common use is to cap how much memory and time a query may take, so one user cannot exhaust the server. Define a limited profile and a default:

spec:
  configuration:
    profiles:
      limited/max_memory_usage: 2000000000
      limited/max_execution_time: 60
      limited/readonly: 0
      default/max_memory_usage: 10000000000

The limited profile caps queries at roughly 2 gigabytes of memory and 60 seconds. Because we set analyst/profile: limited above, the analyst inherits these limits automatically. Profiles keep per-user configuration tidy and consistent.

Quotas: limiting usage over time

Where a profile limits a single query, a quota limits cumulative usage over a rolling window, for example queries per hour. Define the standard quota referenced by our user:

spec:
  configuration:
    quotas:
      standard/interval/duration: 3600
      standard/interval/queries: 10000
      standard/interval/errors: 1000

This allows the analyst up to 10,000 queries and 1,000 errors per hour. Quotas protect the cluster from runaway clients and noisy neighbours.

Server settings and configuration files

The settings block holds server-wide ClickHouse settings, written as paths. For example, raise the logging level or tune a server option:

spec:
  configuration:
    settings:
      logger/level: information
      max_concurrent_queries: 100

For anything that does not fit the structured blocks, the files block lets you supply raw configuration file content that the operator mounts into the pods. You will rarely need it as a beginner, but it is there for advanced tuning and for dictionaries.

Storing passwords in Kubernetes Secrets

A hash in a manifest is better than a plain password, but the cleanest approach keeps the secret out of the CHI entirely, in a Kubernetes Secret. First create the Secret:

kubectl create secret generic ch-credentials \
  -n ch \
  --from-literal=analyst_password='StrongPassw0rd'

Then reference it from the user with valueFrom.secretKeyRef, instead of writing any password or hash in the manifest:

spec:
  configuration:
    users:
      analyst/password:
        valueFrom:
          secretKeyRef:
            name: ch-credentials
            key: analyst_password
      analyst/networks/ip:
        - 0.0.0.0/0

The secretKeyRef names the Secret and the key inside it; the operator looks for the Secret in the same namespace as the cluster and reads the password from it at deploy time, so your CHI, which often lives in version control, contains no credentials at all. This is the recommended pattern for real deployments, because Secrets can be access-controlled and rotated independently of your manifests. (An older k8s_secret_password prefix syntax exists in tutorials, but it has been deprecated since operator 0.23.x in favour of secretKeyRef, so prefer this form.)

Putting it together

Here is a complete, configured single node. Save it as ch-config.yaml:

apiVersion: "clickhouse.altinity.com/v1"
kind: "ClickHouseInstallation"
metadata:
  name: "config-demo"
spec:
  configuration:
    users:
      analyst/password:
        valueFrom:
          secretKeyRef:
            name: ch-credentials
            key: analyst_password
      analyst/networks/ip:
        - 0.0.0.0/0
      analyst/profile: limited
      analyst/quota: standard
    profiles:
      limited/max_memory_usage: 2000000000
      limited/max_execution_time: 60
    quotas:
      standard/interval/duration: 3600
      standard/interval/queries: 10000
    settings:
      max_concurrent_queries: 100
    clusters:
      - name: "main"
        layout:
          shardsCount: 1
          replicasCount: 1
  templates:
    podTemplates:
      - name: clickhouse-pod
        spec:
          containers:
            - name: clickhouse
              image: clickhouse/clickhouse-server:26.3

Create the namespace and Secret, then apply:

kubectl create namespace ch
kubectl create secret generic ch-credentials -n ch \
  --from-literal=analyst_password='StrongPassw0rd'
kubectl apply -n ch -f ch-config.yaml

Once the CHI reports Completed, connect as the analyst and confirm the limits apply by checking a setting:

kubectl port-forward -n ch svc/clickhouse-config-demo 8123:8123
curl 'http://localhost:8123/?user=analyst&password=StrongPassw0rd' \
  --data-binary "SELECT name, value FROM system.settings WHERE name='max_memory_usage'"

You will see the 2 gigabyte cap from the profile in effect.

Clean up

kubectl delete namespace ch

What is next

Your database is configured and its credentials are safe. Everything so far has been a single node. To make ClickHouse fault tolerant we need replication, and replication needs a coordination service. In the next article we deploy ClickHouse Keeper on Kubernetes, the foundation for the replicated cluster we build right after.

References

Work with Quantrail

Expert ClickHouse services

We design, migrate, tune, and run ClickHouse for teams that own their data, from first architecture through day-two operations. Tell us what you are building and we will help.

Talk to an expert

Manage ClickHouse with CHOps

CHOps is our free, open-source ClickHouse admin tool: monitoring, query profiling, backups, visual access control, and alerting in one self-hosted interface, with zero agents on your servers.

Explore CHOps
Share: