TLS keeps log events, credentials, and API requests from crossing the network in clear text while a Logstash pipeline receives data and forwards it to Elasticsearch. That matters when shippers, pipeline hosts, and cluster nodes sit on separate subnets, behind load balancers, or on infrastructure where plaintext traffic would expose operational data.
In a typical secured pipeline, the beats input listens with a server certificate and private key, and the elasticsearch output connects to an HTTPS endpoint that presents a certificate chain the Logstash host trusts. Current plugin settings use names such as ssl_enabled, ssl_certificate, ssl_key, and ssl_certificate_authorities, so the pipeline must align certificate files, host names, and trust anchors on both sides of the flow.
Current beats input releases expect a PEM-encoded PKCS8 private key, and current output plugins fail when older SSL setting names such as ssl or cacert remain in the configuration. Package-based validation is also safest under the logstash service account because current releases block superuser runs by default unless that behavior has been changed explicitly.
Steps to secure Logstash pipelines with TLS:
- Create a directory for the TLS assets on the Logstash host.
$ sudo install -d -o root -g logstash -m 750 /etc/logstash/certs
The logstash group needs read access to the private key, but the directory should stay closed to unrelated users.
- Convert the Logstash listener private key to PEM PKCS8 format when the existing key is still in the older PEM key format.
$ openssl pkcs8 -inform PEM -in /tmp/logstash.key -topk8 -nocrypt -out /tmp/logstash.pkcs8.key
Current Elastic plugin documentation for the beats input expects the private key file referenced by ssl_key to be PEM PKCS8.
- Install the certificate files that the pipeline needs.
$ sudo install -o root -g root -m 644 /tmp/http-ca.crt /etc/logstash/certs/http-ca.crt $ sudo install -o root -g root -m 644 /tmp/logstash-ca.crt /etc/logstash/certs/logstash-ca.crt $ sudo install -o root -g root -m 644 /tmp/logstash.crt /etc/logstash/certs/logstash.crt $ sudo install -o root -g logstash -m 640 /tmp/logstash.pkcs8.key /etc/logstash/certs/logstash.pkcs8.key
Use the CA that signed the Elasticsearch HTTP certificate for /etc/logstash/certs/http-ca.crt. If Elasticsearch already uses a publicly trusted certificate, the output block often does not need a separate CA file.
Keep a copy of /etc/logstash/certs/logstash-ca.crt for shipper-side trust or one-off listener checks such as openssl s_client.
The server certificate presented on the beats listener must match the DNS name or IP address that shippers actually connect to, or TLS host verification fails even when the CA file is correct.
- Verify the installed file modes and ownership before editing the pipeline.
$ sudo ls -l /etc/logstash/certs -rw-r--r-- 1 root root 1115 Apr 8 10:06 http-ca.crt -rw-r--r-- 1 root root 1115 Apr 8 10:06 logstash-ca.crt -rw-r--r-- 1 root root 1184 Apr 8 10:06 logstash.crt -rw-r----- 1 root logstash 1704 Apr 8 10:06 logstash.pkcs8.key
The certificate files can stay world-readable, but the private key should remain readable only by root and the logstash group.
- Configure the TLS-enabled beats input and the HTTPS elasticsearch output in a pipeline file such as /etc/logstash/conf.d/70-tls.conf.
input { beats { port => 5044 ssl_enabled => true ssl_certificate => "/etc/logstash/certs/logstash.crt" ssl_key => "/etc/logstash/certs/logstash.pkcs8.key" } } output { elasticsearch { hosts => ["https://elasticsearch.example.net:9200"] ssl_enabled => true ssl_certificate_authorities => ["/etc/logstash/certs/http-ca.crt"] user => "logstash_writer" password => "${LOGSTASH_ES_PASSWORD}" } }Current plugin releases reject older SSL setting names such as ssl on the output block or cacert in place of ssl_certificate_authorities. Use the current names or the pipeline can fail to start.
Add ssl_certificate_authorities plus ssl_client_authentication => "required" to the beats input only when shippers must present client certificates for mutual TLS.
Keep the password in the Logstash keystore or another secret store instead of writing a real password directly in the pipeline file.
- Test the saved 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 [2026-04-08T00:47:51,483][INFO ][logstash.runner ] Starting Logstash {"logstash.version"=>"9.3.2"} Configuration OK [2026-04-08T00:47:53,445][INFO ][logstash.runner ] Using config.test_and_exit mode. Config Validation Result: OK. Exiting LogstashThe 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 releases block superuser runs by default, so the same command fails as root unless allow_superuser has been changed intentionally.
- Restart the Logstash service so the updated TLS settings are loaded.
$ sudo systemctl restart logstash.service
Restarting Logstash pauses every active pipeline while inputs reopen, filters recompile, and outputs reconnect.
- Review the recent Logstash journal for the listener startup and the secured Elasticsearch output initialization.
$ sudo journalctl --unit=logstash --since "5 minutes ago" --no-pager --lines=20 Apr 08 08:24:11 host logstash[21457]: [2026-04-08T08:24:11,351][INFO ][logstash.outputs.elasticsearch][main] Elasticsearch pool URLs updated {:changes=>{:removed=>[], :added=>[https://elasticsearch.example.net:9200/]}} Apr 08 08:24:11 host logstash[21457]: [2026-04-08T08:24:11,884][INFO ][logstash.javapipeline ][main] Pipeline started {"pipeline.id"=>"main"}401, 403, or index-privilege messages at this stage mean the TLS path is usually working and the remaining problem is authentication or authorization. Certificate trust or host-name failures are logged separately as TLS errors.
- Verify that the beats listener now presents the expected certificate.
$ openssl s_client -brief -connect 127.0.0.1:5044 -servername logstash.example.net -CAfile /etc/logstash/certs/logstash-ca.crt Connecting to 127.0.0.1 CONNECTION ESTABLISHED Protocol version: TLSv1.3 Ciphersuite: TLS_AES_256_GCM_SHA384 Peer certificate: CN=logstash.example.net Verification: OK DONE
This check proves that the listener is up, the certificate chain is trusted by the supplied CA file, and the name used with -servername matches the certificate.
- Verify the outbound HTTPS path to Elasticsearch with the same CA that the output plugin uses.
$ 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.
If this request fails with a certificate error, the Logstash output plugin usually fails for the same CA or host-name reason until the certificate chain or target host name is corrected.
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.
