Skip to content

Enable TLS for Elasticsearch

Severity: highApplies to: Elasticsearch 8.x / 9.x (auto-configured)Applies to: Elasticsearch 7.x (manual)
The fix/etc/elasticsearch/elasticsearch.yml
xpack.security.http.ssl:
enabled: true
keystore.path: certs/http.p12
xpack.security.transport.ssl:
enabled: true
keystore.path: certs/transport.p12
truststore.path: certs/transport.p12
verification_mode: certificate

On 8.x and 9.x, auto-configuration writes exactly this on first start. The work here is usually not undoing it and getting clients to trust the CA.

Elasticsearch has two TLS layers, and they protect different things:

  • Transport TLS (9300) encrypts and authenticates traffic between nodes — replication, cluster state, the actual documents moving around. Without it, a multi-node cluster gossips your entire dataset across the network in plaintext, and — worse — any host that can reach 9300 can attempt to join the cluster and be handed data.
  • HTTP TLS (9200) encrypts the client-to-cluster API, including the authentication credentials on every request.

Without either, the network sees everything. And Elasticsearch’s own authentication is undermined by plaintext HTTP: the credentials it checks are sent in the clear on the way in.

Transport TLS is not optional on a multi-node cluster

Section titled “Transport TLS is not optional on a multi-node cluster”

This is the part that isn’t a hardening nicety — it’s a requirement.

With security enabled, Elasticsearch will not form a multi-node cluster without transport TLS. The nodes must authenticate to each other, and certificate-based transport authentication is how. A cluster with security on and transport TLS off either refuses to start or the nodes never join.

So on a real cluster you are not choosing whether to enable transport TLS — you’re choosing whether to enable it correctly. verification_mode: certificate (the auto-config default) checks that the presented certificate is signed by your CA; full additionally checks the hostname. certificate is the pragmatic choice because node IPs change; full is stricter if your node names are stable.

8.x/9.x did this for you — don’t undo it

Section titled “8.x/9.x did this for you — don’t undo it”

The single most common TLS “problem” on modern Elasticsearch is a client that won’t connect because it doesn’t trust the auto-generated CA, and the “fix” someone applies is to disable TLS or security entirely.

The auto-generated CA is at a known path:

Terminal window
/etc/elasticsearch/certs/http_ca.crt

Point clients at it rather than turning the encryption off:

Terminal window
curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic https://localhost:9200/

For applications, distribute that CA certificate and configure the client to trust it. That’s the correct fix — the certificate being self-signed is not a reason to disable TLS, it’s a reason to install the CA.

On 7.x, none of this is automatic. You generate certificates with elasticsearch-certutil and configure both xpack.security.transport.ssl and xpack.security.http.ssl by hand. It’s more work, it’s well documented, and it’s another reason to be on 8.x or 9.x — the auto-configuration removed the step people most often skipped.