TLS on both hops keeps log events, credentials, and API calls from crossing the network in clear text, which matters when Filebeat shippers, Logstash pipeline hosts, and Elasticsearch nodes are separated by VLANs, proxies, or other shared infrastructure.
In this path, Filebeat opens a Beats connection to Logstash, and Logstash sends bulk requests to Elasticsearch over the HTTP API. Each client validates the certificate chain presented by the server it connects to, so the Logstash listener needs its own server certificate and Elasticsearch needs an HTTPS certificate chain that the Logstash host trusts.
Current Logstash releases reject older TLS option names such as ssl and ssl_verify_mode, and package-based 9.x workflows should validate the pipeline as the logstash service account because superuser runs are blocked by default. The certificate names must match the host names that Filebeat and Logstash actually use, and any private CA in the chain must be copied to each client host that needs to trust it.
Steps to secure Filebeat, Logstash, and Elasticsearch traffic with TLS:
- Confirm that the Elasticsearch HTTP certificate and the Logstash listener certificate both cover the exact DNS names or IP addresses that clients use.
Hostname verification fails when Filebeat or Logstash connects to a name that is missing from the certificate subjectAltName extension. Use an IP SAN when the connection target is an IP address.
- Install the Elasticsearch HTTP CA certificate on the Logstash host.
$ sudo install -d -o root -g logstash -m 750 /etc/logstash/certs $ sudo install -o root -g root -m 644 /tmp/http-ca.crt /etc/logstash/certs/http-ca.crt
Current self-managed Elasticsearch package installs usually create /etc/elasticsearch/certs/http_ca.crt on first startup when security auto-configuration enables HTTPS. If port 9200 is still plain HTTP, complete the Elasticsearch HTTP TLS workflow first and copy the resulting HTTP CA file here.
- Install the Logstash server certificate on the Logstash host.
$ sudo install -o root -g root -m 644 /tmp/logstash.crt /etc/logstash/certs/logstash.crt
The certificate chain presented on port 5044 should include any intermediate CA certificates that Filebeat must trust.
- Install the matching PEM PKCS8 private key on the Logstash host.
$ sudo install -o root -g logstash -m 640 /tmp/logstash.pkcs8.key /etc/logstash/certs/logstash.pkcs8.key
Current beats input releases expect a PEM PKCS8 key. Convert an older PEM key when needed with openssl pkcs8 -inform PEM -in /tmp/logstash.key -topk8 -nocrypt -out /tmp/logstash.pkcs8.key.
Overly broad private-key permissions weaken the listener identity, while an unreadable key prevents the Logstash pipeline from starting.
- Configure the TLS-enabled beats input in /etc/logstash/conf.d/20-beats-input.conf.
input { beats { port => 5044 ssl_enabled => true ssl_certificate => "/etc/logstash/certs/logstash.crt" ssl_key => "/etc/logstash/certs/logstash.pkcs8.key" } }Add ssl_certificate_authorities plus ssl_client_authentication ⇒ “required” only when the design also requires mutual TLS from the Filebeat side.
- Configure the elasticsearch output in /etc/logstash/conf.d/30-output.conf to use HTTPS and the copied HTTP CA.
output { elasticsearch { hosts => ["https://elasticsearch.example.net:9200"] ssl_enabled => true ssl_certificate_authorities => ["/etc/logstash/certs/http-ca.crt"] user => "logstash_internal" password => "${LOGSTASH_INTERNAL_PASSWORD}" ilm_enabled => false index => "logs-%{+YYYY.MM.dd}" } }Use a dedicated write user such as logstash_internal instead of the built-in elastic superuser, and keep the password in the Logstash keystore or another secret manager instead of in cleartext pipeline files.
ilm_enabled ⇒ false keeps the explicit daily logs-YYYY.MM.dd pattern in effect. Remove that line when the pipeline should write through ILM or to a data stream instead.
- Test the Logstash pipeline configuration with the packaged settings directory and a temporary data path.
$ sudo -u logstash /usr/share/logstash/bin/logstash --path.settings /etc/logstash --path.data /tmp/logstash-configtest --config.test_and_exit Using bundled JDK: /usr/share/logstash/jdk Configuration OK [2026-04-07T08:03:34,546][INFO ][logstash.runner ] Using config.test_and_exit mode. Config Validation Result: OK. Exiting Logstash
The temporary --path.data directory must be writable by the logstash user and keeps the validation away from the service data directory in /var/lib/logstash.
Current 9.x packages default allow_superuser to false, so running this check as root fails unless that setting was changed explicitly.
- Restart the Logstash service so the updated TLS listener and HTTPS output are loaded.
$ sudo systemctl restart logstash.service
Restarting Logstash pauses every active pipeline while inputs reopen, filters recompile, and outputs reconnect.
- Review recent Logstash logs for listener startup, pipeline start, and HTTPS output initialization.
$ sudo journalctl --unit logstash --since "5 minutes ago" --no-pager Apr 07 14:24:11 host logstash[21457]: [2026-04-07T14:24:11,351][INFO ][logstash.outputs.elasticsearch][main] Elasticsearch pool URLs updated {:changes=>{:removed=>[], :added=>[https://elasticsearch.example.net:9200/]}} Apr 07 14:24:11 host logstash[21457]: [2026-04-07T14:24:11,884][INFO ][logstash.javapipeline ][main] Pipeline started {"pipeline.id"=>"main"} ##### snipped #####401, 403, or index privilege errors in this stage mean the TLS path to Elasticsearch is up and the remaining problem is credentials, privileges, or index management. Certificate trust, hostname, or protocol failures are logged separately as TLS errors.
- Install the CA certificate that signed the Logstash listener certificate on the Filebeat host.
$ sudo install -d -m 750 /etc/filebeat/certs $ sudo install -m 644 /tmp/logstash-ca.crt /etc/filebeat/certs/logstash-ca.crt
If the same internal CA signed both the Logstash listener certificate and any optional Filebeat client certificate, one CA file can cover both trust checks.
- Configure Filebeat to publish to the TLS-enabled Logstash listener.
output.logstash: hosts: ["logstash.example.net:5044"] ssl.certificate_authorities: ["/etc/filebeat/certs/logstash-ca.crt"] # ssl.certificate: "/etc/filebeat/certs/filebeat.crt" # ssl.key: "/etc/filebeat/certs/filebeat.key"
Keep only one output.* block enabled in /etc/filebeat/filebeat.yml, or Filebeat fails to start with conflicting publisher settings.
Uncomment ssl.certificate and ssl.key only when the Logstash beats input is configured for mutual TLS with ssl_client_authentication.
- Test the saved Filebeat configuration before touching the running service.
$ sudo filebeat test config -c /etc/filebeat/filebeat.yml Config OK
Related: How to test a Filebeat configuration
- Test the Filebeat output against the TLS-enabled Logstash endpoint.
$ sudo filebeat test output -c /etc/filebeat/filebeat.yml logstash: logstash.example.net:5044... connection... parse host... OK dns lookup... OK addresses: 192.0.2.25 dial up... OK TLS... security: server's certificate chain verification is enabled handshake... OK TLS version: TLSv1.3 dial up... OK talk to server... OKThis one-shot check proves the saved host, port, CA file, and certificate name all align before a live event is shipped.
Unknown CA errors usually mention certificate signed by unknown authority, while host name mismatches usually mention the requested host not appearing in the certificate.
- Restart the Filebeat service so live events move through the secured Logstash path.
$ sudo systemctl restart filebeat.service
- Review recent Filebeat logs for the post-restart Logstash connection.
$ sudo journalctl --unit=filebeat --since "5 min ago" --no-pager --lines=20 Apr 08 02:14:56 web-01 filebeat[2147]: {"log.level":"info","@timestamp":"2026-04-08T02:14:56.197Z","log.logger":"publisher_pipeline_output","message":"Connecting to backoff(async(tcp://logstash.example.net:5044))","service.name":"filebeat","ecs.version":"1.6.0"} Apr 08 02:14:56 web-01 filebeat[2147]: {"log.level":"info","@timestamp":"2026-04-08T02:14:56.316Z","log.logger":"publisher_pipeline_output","message":"Connection to backoff(async(tcp://logstash.example.net:5044)) established","service.name":"filebeat","ecs.version":"1.6.0"}The journal confirms that the running service, not only the one-shot test command, reconnected to the configured Logstash output after the restart.
If this line never appears, review the Logstash journal at the same time for listener, certificate, or pipeline startup failures.
- Verify that the Elasticsearch HTTP endpoint now answers over HTTPS with the trusted CA chain.
$ curl --silent --show-error --output /dev/null --write-out "%{http_code}\n" --cacert /etc/logstash/certs/http-ca.crt https://elasticsearch.example.net:9200/ 401A validated 401 response proves that the TLS handshake succeeded and that the endpoint is enforcing authentication instead of serving plaintext HTTP.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
