Security Guide: Configuration
This page is the procedural reference for hardening a Logster deployment. It covers authentication, CORS, TLS, reverse-proxy setup, Elasticsearch security, and Kafka transport security, with step-by-step instructions for each.
Read Overview and Security Validations first if you haven't — this page assumes you already understand what needs to be protected and why.
Authentication
The problem
The default Logster build has no authentication on the dashboard,
REST API, Kibana, Prometheus, or Tempo. Only Grafana has a default
password (admin / logster), and anonymous read is enabled.
The solution: reverse proxy
The recommended pattern is a single auth-enforcing reverse proxy in front of every user-facing port. This centralizes authentication and lets Logster stay simple internally.
Architecture
┌─────────────────────────────────────────────┐
│ Public / corporate network │
└────────────────────┬────────────────────────┘
│
▼ TLS + auth
┌─────────────────────────────────────────────┐
│ Reverse proxy (nginx / Traefik / Caddy) │
│ - TLS termination │
│ - OIDC / SAML / Basic auth │
│ - /dashboard → :5001 │
│ - /api → :8080 │
│ - /grafana → :3000 │
│ - /kibana → :5601 │
└────────────────────┬────────────────────────┘
│ plaintext, localhost-only
▼
┌─────────────────────────────────────────────┐
│ Logster stack │
└─────────────────────────────────────────────┘
Step 1 — Bind Logster to localhost
Edit deploy/docker-compose.yml
so every published port binds only to 127.0.0.1:
api:
ports:
- "127.0.0.1:8080:8080"
dashboard:
ports:
- "127.0.0.1:5001:5000"
grafana:
ports:
- "127.0.0.1:3000:3000"
kibana:
ports:
- "127.0.0.1:5601:5601"
prometheus:
ports:
- "127.0.0.1:9090:9090"
elasticsearch:
ports:
- "127.0.0.1:9200:9200"
After restarting the stack, nmap from another host should show
every one of these ports as closed.
Step 2 — Deploy a reverse proxy
Use nginx, Traefik, Caddy, or any other auth-enforcing reverse proxy. The proxy must:
- Terminate TLS (TLS 1.2 or newer).
- Enforce authentication on every upstream path.
- Forward to the localhost-bound Logster ports from Step 1.
TBD — reference reverse-proxy configuration. Replace this placeholder with a vetted configuration snippet for your chosen proxy (nginx / Traefik / Caddy). Do not copy an example from generic documentation — test it against a real Logster deployment and verify every published route responds correctly.
Step 3 — Verify
# From outside the host, unauthenticated
curl -i https://<your-logster-fqdn>/api/health
# Expect: 401 Unauthorized
# With valid credentials
curl -u <user>:<password> https://<your-logster-fqdn>/api/health
# Expect: {"status":"ok",...}
TBD — SaaS auth topology. Logster Support's SaaS deployment model for Logster uses its own reverse proxy and identity provider stack. Confirm the exact topology with Logster Support Customer Services before documenting it here.
CORS
The problem
The REST API defaults to api.cors_origins: ["*"] in
deploy/service-config.yaml.
This means any web page on the internet can make authenticated
requests to your API from a user's browser (if the user is behind
the reverse proxy).
The fix
Tighten api.cors_origins to only the origins you actually
serve the dashboard from:
Restart the API:
Verify via browser devtools — a cross-origin request from any other origin should now fail with a CORS error.
TLS
The problem
Every Logster service in the default Compose stack speaks plain HTTP or plain TCP. There is no TLS anywhere in the default build.
The fix
Terminate TLS at the reverse proxy. Do not try to configure TLS inside the individual Logster containers — the architecture assumes plain transport on the internal network.
- Certificates. Use Let's Encrypt (Caddy handles this automatically; nginx/Traefik have plugins), or your corporate CA.
- Minimum protocol version. TLS 1.2 or higher. Disable all older versions at the proxy.
- HSTS. Enable HTTP Strict Transport Security headers so browsers refuse to fall back to plain HTTP.
Optionally, also terminate TLS on internal paths (Kafka broker listeners, Elasticsearch). See the next sections.
Elasticsearch security
The problem
The default Compose stack runs Elasticsearch with
xpack.security.enabled: "false". Anyone who can reach port
9200 has full read/write access.
The fix
Enable ES security in deploy/docker-compose.yml:
elasticsearch:
environment:
discovery.type: single-node
xpack.security.enabled: "true"
ELASTIC_PASSWORD: "<strong-password>"
Then update every service that talks to ES:
- Logstash — add credentials to the pipeline conf files under deploy/logstash/pipeline/.
- Dashboard — set the dashboard's Elasticsearch client to use
basic auth. Update
ES_HOSTtohttp://elastic:<password>@elasticsearch:9200. - Kibana — add
ELASTICSEARCH_USERNAMEandELASTICSEARCH_PASSWORDenvironment variables.
Restart the full stack and verify:
Kafka authentication
The problem
The default Kafka broker uses PLAINTEXT listeners with no
authentication. Anyone who can reach the broker can publish to any
topic — which means injecting fake events into sysmon-logs,
deleting messages from logster-alerts, or draining
normalized-endpoint-events.
The fix
Use SASL/SSL in production. The high-level steps are:
- Provision SASL credentials for each Kafka client (a principal per service and per log shipper).
- Configure Kafka ACLs so each principal has only the read / write permissions it needs. The mapping of service to topic access is derivable from the architecture — the normalizer reads the raw topics and writes the normalized topic, and so on. See Enterprise Architecture.
- Reconfigure the Compose file to use
SASL_SSLlisteners, mount the truststore/keystore, and enable broker-side ACL enforcement. - Update
kafka.brokersin deploy/service-config.yaml to the new listener address, and pass SASL credentials via environment variables.
TBD — concrete SASL configuration. Document your production-validated Kafka SASL/SSL configuration here, including the exact principal-to-topic ACL mapping, once it has been tested against a real multi-broker cluster. The dev single-broker KRaft stack does not exercise ACL enforcement.
This is the largest single hardening step in this guide and is usually best handled by your platform team as part of their existing Kafka operations practice.
Grafana
The problem
The default Grafana admin password is logster and anonymous read
is enabled.
The fix
grafana:
environment:
GF_SECURITY_ADMIN_PASSWORD: "<strong-password>"
GF_AUTH_ANONYMOUS_ENABLED: "false"
Restart Grafana:
Now only authenticated users can view or modify dashboards. Consider also enabling Grafana's OAuth/OIDC integration to avoid a second set of credentials for analysts.
Multi-tenancy
Logster's data model includes a tenant_id on every event, every
inference, and every alert. The default build does not enforce
isolation between tenants at the API layer — any caller can pass
any tenant ID to GET /alerts?tenant_id=....
Two patterns
Pattern A — one instance per tenant. Run a separate Logster stack per tenant, with tenant data never commingled on the same Kafka topics or ES indices. Simple, strong, and the recommended approach unless you have a good reason otherwise.
Pattern B — multi-tenant in one instance, enforced at the
proxy. Run one stack and use a reverse proxy to inject a
hard-coded tenant_id query parameter on every request, based on
the authenticated user's tenant. The proxy must strip any
tenant_id the client tries to submit.
[!WARNING] Pattern B is fragile. Any bug or misconfiguration that lets a tenant ID through from the client leaks data across tenants. Pattern A is strongly preferred.
Production hardening checklist
- [ ] Reverse proxy in front of every user-facing port
- [ ] TLS terminated at the proxy, TLS 1.2+
- [ ] Ports bound to
127.0.0.1in the Compose file - [ ]
api.cors_originsrestricted to dashboard origin(s) - [ ] Grafana password rotated, anonymous access disabled
- [ ] Elasticsearch security enabled, credentials provisioned
- [ ] Kafka on SASL/SSL with ACLs
- [ ] Alert store swapped to Postgres (see Admin Guide: Important Considerations)
- [ ] Model file checksums verified on every deploy
- [ ] Audit logging captured at the proxy layer
For the full hardening list, see Admin Guide: Important Considerations.
Where to go next
- Overview — threat model.
- Security Validations — what the pipeline validates on its own.
- Admin Guide: Authentication — the operator-facing short form of this page.