New to KubeDB? Please start here.

Run Elasticsearch with TLS/SSL (Transport Encryption)

KubeDB supports providing TLS/SSL encryption for Elasticsearch. This tutorial will show you how to use KubeDB to run an Elasticsearch combined 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-manager 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/elasticsearch folder in GitHub repository kubedb/docs.

Overview

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

  • spec:
    • enableSSL
    • tls:
      • issuerRef
      • certificates

Read about the fields in details in elasticsearch concept.

tls is applicable for all types of Elasticsearch (i.e., combined and topology).

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.certificates to generate certificate secrets. These certificate secrets are then used to configure TLS for both the transport layer (node-to-node communication) and the HTTP layer (client-to-node communication), containing ca.crt, tls.crt and tls.key.

Note: tls.issuerRef is optional. A user can deploy Elasticsearch without creating an Issuer/ClusterIssuer by just setting enableSSL: true. In that case, the KubeDB Elasticsearch operator automatically creates a self-signed CA and the necessary certificate secrets.

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 Elasticsearch. Alternatively, you can follow this cert-manager tutorial to create your own Issuer.

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

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: es-ca-issuer
  namespace: demo
spec:
  ca:
    secretName: es-ca

Apply the YAML file:

$ kubectl create -f https://github.com/kubedb/docs/raw/v2026.4.27/docs/examples/elasticsearch/tls/es-issuer.yaml
issuer.cert-manager.io/es-ca-issuer created

TLS/SSL encryption in Elasticsearch Combined Cluster

apiVersion: kubedb.com/v1
kind: Elasticsearch
metadata:
  name: es-combined-tls
  namespace: demo
spec:
  version: xpack-8.19.9
  enableSSL: true
  tls:
    issuerRef:
      apiGroup: "cert-manager.io"
      kind: Issuer
      name: es-ca-issuer
  replicas: 3
  storage:
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 1Gi
    storageClassName: standard
  storageType: Durable
  deletionPolicy: WipeOut

Deploy Elasticsearch Combined Cluster

$ kubectl create -f https://github.com/kubedb/docs/raw/v2026.4.27/docs/examples/elasticsearch/tls/es-combined-tls.yaml
elasticsearch.kubedb.com/es-combined-tls created

Now, wait until es-combined-tls has status Ready. i.e,

$ kubectl get es -n demo -w
NAME              VERSION        STATUS         AGE
es-combined-tls   xpack-8.19.9   Provisioning   0s
es-combined-tls   xpack-8.19.9   Provisioning   15s
.
.
es-combined-tls   xpack-8.19.9   Ready          82s

Verify TLS/SSL in Elasticsearch Combined Cluster

KubeDB creates a client certificate secret for Elasticsearch. Let’s check it:

$ kubectl describe secret -n demo es-combined-tls-client-cert
Name:         es-combined-tls-client-cert
Namespace:    demo
Labels:       app.kubernetes.io/component=database
              app.kubernetes.io/instance=es-combined-tls
              app.kubernetes.io/managed-by=kubedb.com
              app.kubernetes.io/name=elasticsearches.kubedb.com
              controller.cert-manager.io/fao=true
Annotations:  cert-manager.io/alt-names:
                *.es-combined-tls-pods.demo.svc,*.es-combined-tls-pods.demo.svc.cluster.local,es-combined-tls,es-combined-tls.demo.svc,localhost
              cert-manager.io/certificate-name: es-combined-tls-client-cert
              cert-manager.io/common-name: es-combined-tls
              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: es-ca-issuer
              cert-manager.io/subject-organizations: kubedb
              cert-manager.io/uri-sans: 

Type:  kubernetes.io/tls

Data
====
tls.key:  1708 bytes
ca.crt:   1172 bytes
tls.crt:  1387 bytes

Now, let’s exec into an Elasticsearch pod and verify the configuration that TLS is enabled for both transport and HTTP layers.

$ kubectl exec -n demo es-combined-tls-0 -c elasticsearch -- \
                                      cat /usr/share/elasticsearch/config/elasticsearch.yml | grep -A 2 -i xpack.security
xpack.security.enabled: true

xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.key: certs/transport/tls.key
xpack.security.transport.ssl.certificate: certs/transport/tls.crt 
xpack.security.transport.ssl.certificate_authorities: [ "certs/transport/ca.crt" ]

xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.key:  certs/http/tls.key
xpack.security.http.ssl.certificate: certs/http/tls.crt
xpack.security.http.ssl.certificate_authorities: [ "certs/http/ca.crt" ]

We can see from the above output that both xpack.security.transport.ssl.enabled: true and xpack.security.http.ssl.enabled: true are set, which means TLS is enabled for both node-to-node and client-to-node communication.

Now, let’s connect to the Elasticsearch cluster using HTTPS to confirm it is accessible with TLS.

$  kubectl exec -it -n demo es-combined-tls-0 -c elasticsearch -- curl -k -XGET "https://localhost:9200/_cluster/health?pretty" --user "elastic:$ELASTIC_USER_PASSWORD"
{
  "cluster_name" : "es-combined-tls",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 3,
  "number_of_data_nodes" : 3,
  "active_primary_shards" : 4,
  "active_shards" : 8,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "unassigned_primary_shards" : 0,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 100.0
}

From the above output, we can see that we are able to connect to the Elasticsearch cluster using the TLS configuration.

Cleaning up

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

kubectl delete es -n demo es-combined-tls
kubectl delete issuer -n demo es-ca-issuer
kubectl delete secret -n demo es-ca
kubectl delete ns demo

Next Steps