You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(security): bind Grafana to loopback and gate wide exposure on an admin password
RenderMonitoringCompose emitted the Grafana service with an unconditional
host port publication and no environment block at all - no
GF_SECURITY_ADMIN_PASSWORD, no auth hardening - so the deployed container
kept grafana-oss's built-in admin/admin while docker published it on
0.0.0.0. On a cloud VM with a permissive security group that is the public
internet: full node metrics, the ability to lock the operator out, and -
because a Grafana admin can add arbitrary datasources and query them
through the backend proxy - a server-side request primitive into the
host's internal network and cloud metadata endpoints.
Grafana is now bound to 127.0.0.1 by default. A new
monitoring.grafana.expose restores the wide bind, but is rejected unless
monitoring.grafana.admin_password_env is also set, so the escape hatch
cannot recreate the finding; the renderer independently falls back to
loopback for an unvalidated intent. The password is rendered as a required
compose variable reference, so the secret never enters the 0644 compose
file and an unset or empty value fails at interpolation before any
container is created.
Verified against real Docker: the default resolves to host_ip 127.0.0.1,
and expose without a password falls back to loopback.
Breaking: Grafana is no longer reachable off-host by default. Use an SSH
tunnel, a reverse proxy, or the new expose opt-in.
Copy file name to clipboardExpand all lines: README.md
+14-1Lines changed: 14 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -370,7 +370,20 @@ trond network status
370
370
|`trond status` / `trond inspect <node> -o json`| Expose the stack's `prometheus_port` / `grafana_port` so agents can discover it |
371
371
|`trond remove <node>` / `trond network destroy`| Automatically cleans up the monitoring stack |
372
372
373
-
After deployment, Grafana is available at http://localhost:3000 (admin/admin) with 5 dashboards: java-tron-server, java-tron-api, java-tron-api-statistic, java-tron-mechanism, and node-exporter-full. Prometheus is at http://localhost:9090.
373
+
After deployment, Grafana is available at http://localhost:3000 — **on the deployment host's loopback interface only** — with 5 dashboards: java-tron-server, java-tron-api, java-tron-api-statistic, java-tron-mechanism, and node-exporter-full. Prometheus is at http://localhost:9090.
374
+
375
+
Grafana keeps the image's default `admin/admin` login until you give it a password, so it is bound to `127.0.0.1`: reach it from your workstation over an SSH tunnel (`ssh -L 3000:127.0.0.1:3000 user@host`) or a reverse proxy you control. To publish it on all interfaces instead, opt in explicitly — which requires an admin password:
376
+
377
+
```yaml
378
+
monitoring:
379
+
enabled: true
380
+
grafana:
381
+
port: 3000
382
+
expose: true # bind 0.0.0.0 instead of 127.0.0.1
383
+
admin_password_env: GRAFANA_ADMIN_PASSWORD # NAME of an env var, not the password
384
+
```
385
+
386
+
`GRAFANA_ADMIN_PASSWORD` must be set in the environment that runs `trond apply` (compose refuses to start the stack otherwise). Grafana applies it when it first initialises its database, so rotate the password in Grafana itself for a stack that is already running.
374
387
375
388
**Limitations**: The single Prometheus instance loses visibility into nodes isolated by `trond partition`; metrics resume after `trond heal`. Monitoring is Docker-only (Prometheus and Grafana run as containers), so jar-runtime targets need Docker on the trond machine for the monitoring stack.
returnfmt.Errorf("monitoring.grafana.admin_password_env %q is not a valid environment variable name; it must be the NAME of an env var holding the Grafana admin password (e.g., GRAFANA_ADMIN_PASSWORD), not the password itself", m.Grafana.AdminPasswordEnv)
// Publishing Grafana beyond loopback with the image's default
454
+
// admin/admin login hands the dashboards and the datasource proxy
455
+
// to anyone who can reach the port.
456
+
returnfmt.Errorf("monitoring.grafana.expose publishes Grafana on all host interfaces and therefore requires monitoring.grafana.admin_password_env: set it to the NAME of an environment variable holding the admin password (e.g., admin_password_env: GRAFANA_ADMIN_PASSWORD), or drop expose to keep Grafana bound to 127.0.0.1")
0 commit comments