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-managerv1.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
demothroughout 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:enableSSLtls:issuerRefcertificates
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.issuerRefis optional. A user can deploy Elasticsearch without creating anIssuer/ClusterIssuerby just settingenableSSL: 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
- Detail concepts of Elasticsearch object.
- Different Elasticsearch topology clustering modes here.
- Monitor your Elasticsearch database with KubeDB using out-of-the-box Prometheus operator.
- Want to hack on KubeDB? Check our contribution guidelines.































