New to KubeDB? Please start here.

Run ClickHouse with TLS/SSL (Transport Encryption)

KubeDB supports providing TLS/SSL encryption for ClickHouse. This tutorial will show you how to use KubeDB to run a ClickHouse cluster with TLS/SSL encryption.

Before You Begin

  • At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using kind.

  • Install cert-manger v1.0.0 or later to your cluster to manage your SSL/TLS certificates.

  • Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps here.

  • To keep things isolated, this tutorial uses a separate namespace called demo throughout this tutorial.

    $ kubectl create ns demo
    namespace/demo created
    

Note: YAML files used in this tutorial are stored in docs/examples/clickhouse folder in GitHub repository kubedb/docs.

Overview

KubeDB uses following crd fields to enable SSL/TLS encryption in ClickHouse.

  • spec:
    • tls:
      • issuerRef
      • certificate

Read about the fields in details in clickhouse concept,

tls is applicable for all types of ClickHouse (i.e., standalone and clickhouse).

Users must specify the tls.issuerRef field. KubeDB uses the issuer or clusterIssuer referenced in the tls.issuerRef field, and the certificate specs provided in tls.certificate to generate certificate secrets. These certificate secrets are then used to generate required certificates including ca.crt, tls.crt, tls.key.

Create Issuer/ ClusterIssuer

We are going to create an example Issuer that will be used throughout the duration of this tutorial to enable SSL/TLS in ClickHouse. Alternatively, you can follow this cert-manager tutorial to create your own Issuer.

  • Start off by generating you ca certificates using openssl.
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./ca.key -out ./ca.crt -subj "/CN=clickhouse/O=kubedb"
  • Now create a ca-secret using the certificate files you have just generated.
kubectl create secret tls clickhouse-ca \
     --cert=ca.crt \
     --key=ca.key \
     --namespace=demo

Now, create an Issuer using the ca-secret you have just created. The YAML file looks like this:

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: clickhouse-ca-issuer
  namespace: demo
spec:
  ca:
    secretName: clickhouse-ca

Apply the YAML file:

$ kubectl create -f https://github.com/kubedb/docs/raw/v2025.8.31/docs/examples/clickhouse/tls/clickhouse-issuer.yaml
issuer.cert-manager.io/clickhouse-ca-issuer created

TLS/SSL encryption in ClickHouse Cluster

apiVersion: kubedb.com/v1alpha2
kind: ClickHouse
metadata:
  name: clickhouse-prod-tls
  namespace: demo
spec:
  version: 24.4.1
  clusterTopology:
    clickHouseKeeper:
      externallyManaged: false
      spec:
        replicas: 3
        storage:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 1Gi
    cluster:
        name: appscode-cluster
        shards: 2
        replicas: 2
        podTemplate:
          spec:
            containers:
              - name: clickhouse
                resources:
                  limits:
                    memory: 4Gi
                  requests:
                    cpu: 500m
                    memory: 512Mi
            initContainers:
              - name: clickhouse-init
                resources:
                  limits:
                    memory: 1Gi
                  requests:
                    cpu: 500m
                    memory: 512Mi
        storage:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 1Gi
  sslVerificationMode: relaxed
  tls:
    issuerRef:
      apiGroup: "cert-manager.io"
      kind: Issuer
      name: clickhouse-ca-issuer
    certificates:
      - alias: server
        subject:
          organizations:
            - kubedb:server
        dnsNames:
          - localhost
        ipAddresses:
          - "127.0.0.1"
  deletionPolicy: WipeOut

Deploy ClickHouse Topology Cluster with TLS/SSL

$ kubectl create -f https://github.com/kubedb/docs/raw/v2025.8.31/docs/examples/clickhouse/tls/clickhouse-prod-tls.yaml
clickhouse.kubedb.com/clickhouse-prod-tls created

Now, wait until clickhouse-prod-tls created has status Ready. i.e,

➤ kubectl get clickhouse -n demo -w
NAME                  TYPE                  VERSION   STATUS         AGE
clickhouse-prod-tls   kubedb.com/v1alpha2   24.4.1    Provisioning   31s
clickhouse-prod-tls   kubedb.com/v1alpha2   24.4.1    Provisioning   51s
.
.
clickhouse-prod-tls   kubedb.com/v1alpha2   24.4.1    Ready          2m6s

Verify TLS/SSL in ClickHouse Topology Cluster

➤ kubectl describe secret clickhouse-prod-tls-client-cert -n demo
Name:         clickhouse-prod-tls-client-cert
Namespace:    demo
Labels:       app.kubernetes.io/component=database
              app.kubernetes.io/instance=clickhouse-prod-tls
              app.kubernetes.io/managed-by=kubedb.com
              app.kubernetes.io/name=clickhouses.kubedb.com
              controller.cert-manager.io/fao=true
Annotations:  cert-manager.io/alt-names:
                *.clickhouse-prod-tls-pods.demo.svc.cluster.local,clickhouse-prod-tls,clickhouse-prod-tls-pods,clickhouse-prod-tls-pods.demo.svc,clickhous...
              cert-manager.io/certificate-name: clickhouse-prod-tls-client-cert
              cert-manager.io/common-name: clickhouse-prod-tls.demo.svc
              cert-manager.io/ip-sans: 127.0.0.1
              cert-manager.io/issuer-group: cert-manager.io
              cert-manager.io/issuer-kind: Issuer
              cert-manager.io/issuer-name: clickhouse-ca-issuer
              cert-manager.io/uri-sans: 

Type:  kubernetes.io/tls

Data
====
ca.crt:            1164 bytes
tls-combined.pem:  3221 bytes
tls.crt:           1541 bytes
tls.key:           1679 bytes

Now, Let’s exec into a clickhouse pod and verify the configuration that the TLS is enabled.

➤ kubectl exec -it -n demo clickhouse-prod-tls-appscode-cluster-shard-0-0 -- bash
Defaulted container "clickhouse" out of: clickhouse, clickhouse-init (init)
clickhouse@clickhouse-prod-tls-appscode-cluster-shard-0-0:/$ openssl s_client -connect localhost:9440
CONNECTED(00000003)
Can't use SSL_get_servername
depth=1 CN = clickhouse, O = kubedb
verify error:num=19:self signed certificate in certificate chain
verify return:1
depth=1 CN = clickhouse, O = kubedb
verify return:1
depth=0 O = kubedb:server, CN = clickhouse-prod-tls
verify return:1
---
Certificate chain
 0 s:O = kubedb:server, CN = clickhouse-prod-tls
   i:CN = clickhouse, O = kubedb
 1 s:CN = clickhouse, O = kubedb
   i:CN = clickhouse, O = kubedb

We can see from the above output that, tls port is accessible by using openssl which means that TLS is enabled.

Cleaning up

To cleanup the Kubernetes resources created by this tutorial, run:

kubectl delete clickhouse -n demo clickhouse-prod-tls
kubectl delete issuer -n demo clickhouse-ca-issuer
kubectl delete ns demo

Next Steps