Every Logstash node runs an HTTP monitoring API, by default on port 9600. It answers questions like “what pipelines are running”, “what plugins and versions are installed”, and “show me the hottest threads with stack traces”. By default it binds to 127.0.0.1, which is safe. Exposure happens when someone sets api.http.host to 0.0.0.0 or a routable IP to make remote monitoring easier, and leaves it there.

On Logstash versions before 8.x, the API has no built-in authentication at all: anyone who can reach the port can read everything it serves. On 8.x, basic auth and SSL exist but are off by default, so an exposed bind is still unauthenticated unless you explicitly configured it.

This guide covers auditing the bind address, what an exposed API discloses, and how to lock it down without breaking your monitoring stack.

What the monitoring API exposes

The API is read-only, but “read-only” covers a lot of operational detail:

  • Node info. A GET to / returns the Logstash version, JVM version, node name, and pipeline summary. Version disclosure alone hands an attacker a CVE shopping list.
  • Pipeline stats. /_node/stats/pipelines enumerates pipeline IDs, per-plugin throughput, queue sizes, and event counters. This reveals your log sources, destinations, and internal naming conventions.
  • Pipeline configuration detail. /_node/pipelines can expose pipeline configuration structure in some versions. Pipeline configs routinely contain hostnames, index names, and sometimes connection details for Elasticsearch, Kafka, and databases.
  • Hot threads. /_node/hot_threads returns JVM stack traces. Beyond reconnaissance value, requesting hot threads is expensive for the JVM, so an unauthenticated API is also a lightweight denial-of-service vector.
  • JVM and process stats. Heap usage, GC counters, open file descriptors, uptime. Useful for timing attacks against known failure modes like a GC death spiral.

None of this requires a password if the API is bound to a routable interface and auth is not configured. This is information disclosure and reconnaissance surface, plus a potential DoS path, not remote code execution. Treat it as a fix-before-the-audit-finds-it ticket, not a page.

Audit procedure

Work through these steps on every Logstash host. All commands are read-only.

1. Check what address the API is listening on.

# Find the listener for the monitoring API
ss -tlnp | grep 9600

Interpretation:

  • 127.0.0.1:9600 or [::1]:9600: loopback only. Safe from the network, though any local process can still query it.
  • 0.0.0.0:9600 or [::]:9600: listening on all interfaces. Exposed.
  • A specific routable IP (for example 10.0.4.17:9600): exposed on that interface. Whether that is acceptable depends on whether the interface is a management network and whether auth is enabled.

The default port is 9600, but it is configurable via api.http.port, and a second Logstash instance on the same host will take a subsequent port. If ss shows a Java process on 9601 or similar, check that too.

2. Check the configured bind and auth settings.

# Inspect API-related settings
grep -E 'api\.(http\.host|http\.port|enabled|auth|ssl)' /etc/logstash/logstash.yml

An empty result means defaults: api.enabled: true, bound to loopback, no auth, no SSL. If api.http.host is set to 0.0.0.0 or a routable IP and there are no api.auth or api.ssl lines, the API is exposed without authentication.

3. Test reachability from a different host.

Config files can lie: an old http.host setting, an override file, or a container port mapping can change what actually listens. The authoritative test is from off the host:

# Run from another machine that can route to the Logstash host
curl -sS --connect-timeout 5 http://<logstash-host-ip>:9600/

A JSON response with version and pipeline info confirms unauthenticated remote access. A timeout or refusal means the network path is blocked by the bind address or a firewall. A 401 means auth is enabled.

4. Check the Logstash version.

# Version from the API itself (from the host)
curl -sS http://127.0.0.1:9600/ | grep -o '"version":"[^"]*"'

This determines your remediation options. Logstash 8.x supports api.auth.type: basic and API SSL. On 7.x and earlier there is no built-in API auth, so your only controls are the bind address and network-level filtering.

5. Audit pipeline configs for plaintext credentials and loose permissions.

The exposed-API problem and the plaintext-credentials problem usually travel together. While you are on the host:

# Look for secrets in pipeline configs
grep -rn 'password\|api_key\|secret\|token' /etc/logstash/conf.d/

# Check who can read the configs
ls -la /etc/logstash/conf.d/

Pipeline configs frequently contain Elasticsearch passwords, database credentials, and API keys. If they are world-readable, any local user has your downstream credentials. Secrets should live in the Logstash keystore and be referenced as ${SECRET_NAME} in configs, not written inline.

Locking it down

Option 1: bind to loopback (simplest, works on every version)

# /etc/logstash/logstash.yml
api.http.host: 127.0.0.1

This is the right answer when your monitoring agent runs on the same host as Logstash, which is the common case. Restart Logstash to apply. Local collectors, health checks, and curl diagnostics from the host keep working.

Option 2: bind to a management interface with auth and SSL (8.x)

If the API must be reachable remotely, put it on a dedicated management network and turn on authentication:

# /etc/logstash/logstash.yml
api.http.host: 10.0.10.15        # management network interface only
api.ssl.enabled: true
api.auth.type: basic
api.auth.basic.username: logstash_monitor
api.auth.basic.password: ${LOGSTASH_API_PASSWORD}

Store the password in the Logstash keystore rather than inline:

# Add the API password to the keystore (prompts for the value)
logstash-keystore add LOGSTASH_API_PASSWORD

Two important details:

  • Basic auth without SSL sends credentials in cleartext. Anyone on the path can sniff them. Logstash 8.x warns about this combination. If you enable api.auth.type: basic, enable api.ssl.enabled: true as well.
  • Enabling SSL plus basic auth changes the default bind. In 8.x, once api.ssl.enabled: true and api.auth.type: basic are both set, Logstash treats the API as secured and defaults to binding on all interfaces (0.0.0.0) unless you set api.http.host explicitly. Operators routinely secure the API and accidentally widen its exposure in the same change. Always set api.http.host to the specific interface you intend.

Option 3: network-level controls (required for pre-8.x remote access)

On 7.x and earlier there is no auth option. If you genuinely need remote API access from a monitoring host, the only safe pattern is a host firewall or security group rule that allows port 9600 exclusively from the monitoring host’s IP. Prefer upgrading: 7.17 is end of life, and the 8.x auth model removes this entire class of workaround.

Verifying the lockdown

After restarting Logstash, re-run the audit:

# 1. Confirm the listener moved
ss -tlnp | grep 9600

# 2. Confirm remote access is refused or authenticated (from another host)
curl -sS --connect-timeout 5 http://<logstash-host-ip>:9600/

# 3. Confirm local collection still works (from the Logstash host)
curl -sS --connect-timeout 5 http://127.0.0.1:9600/_node/stats/pipelines?pretty

Expected results: the listener shows the intended address, the remote probe either times out (loopback bind) or returns 401 over HTTPS (auth enabled), and local stats queries still return pipeline data. Then confirm your monitoring system is still receiving Logstash metrics. This is the step people skip, and it is how a security fix turns into a silent monitoring outage.

Common pitfalls

  • The 0.0.0.0 trap after enabling auth. As covered above: SSL plus basic auth in 8.x flips the default bind to all interfaces. Verify with ss after every change, not just with the config file.
  • Deprecated setting names. The old http.host, http.port, and http.enabled settings are deprecated in favor of api.http.host, api.http.port, and api.enabled. Mixing old and new names is a configuration error. If a host has been upgraded across major versions, check for leftover http.* lines in logstash.yml.
  • Breaking the monitoring collector. If your metrics collector polls http://<host>:9600 remotely and you rebind to loopback, collection fails. Either run the collector on the Logstash host or point it at the management interface with credentials. A sudden gap in Logstash metrics after a config change is usually this, not a Logstash crash.
  • Container port publishing. In Docker or Kubernetes, a loopback bind inside the container does not help if the port is published or the pod shares a host network. Check the actual listener from outside the container’s network namespace, not just the container’s config.
  • Credentials in config management. If pipeline configs with inline passwords are deployed by Ansible, Puppet, or similar, the secrets also live in the config management repo and its state files. Rotating the Logstash-side storage to the keystore does not clean up the upstream copy.
  • Weak API passwords. Logstash 8.3.0 and later include a password policy for api.auth.basic.password (minimum length and character mix, with a WARN/ERROR enforcement mode). On earlier 8.x releases nothing stops you from setting a trivial password, so enforce strength yourself.

Signals to monitor

SignalWhy it mattersWarning sign
API listener address (ss -tlnp)The ground truth for exposure, independent of config filesListener on 0.0.0.0 or a routable IP without auth configured
api.* settings in logstash.ymlWhere bind, auth, and SSL are controlledapi.http.host set broadly with no api.auth lines; leftover deprecated http.* keys
Config file mtimes on /etc/logstashUnexpected edits outside a deploy window can re-expose the APImtime changes with no corresponding change record
Plaintext secrets in conf.dExposed API plus readable configs compounds into credential disclosurepassword/api_key matches in pipeline configs, or world-readable files
API reachability from the monitoring hostDetects both outages and accidental lockout of your collectorCollector failing while the process is healthy
Unexpected connections to port 9600Reconnaissance or scraping of the APIConnections from IPs other than localhost or the monitoring host

How Netdata helps

  • Netdata’s Logstash collector polls the monitoring API on port 9600, so the audit in this article doubles as a check on how your own metrics are collected. If you rebind or add auth, update the collector configuration at the same time and verify metric continuity.
  • A sudden stop in Logstash charts immediately after a config change is distinguishable from a crash: process and system metrics stay healthy while Logstash-specific charts go flat. Correlating collector reachability with process liveness and JVM uptime separates “API moved” from “Logstash down”.
  • Netdata surfaces the metrics the API serves (pipeline throughput, queue depth, JVM heap, GC, file descriptors) at per-second granularity, so you can watch output throughput continue uninterrupted while you make bind changes, confirming you have not disturbed the pipeline itself.
  • Alerting on API reachability alongside pipeline output rate catches both directions of the problem: an API that disappears (misconfiguration, GC pause, crash) and a pipeline that stops delivering while the API still answers (the “living dead” case).