Problem
metrics-plugin exposes /metrics endpoint in order for scraping services (e.g. Prometheus or Grafana Alloy) to collect CLN metrics. Currently, /metrics is open - if the port is configured to be open for the whole world, potentially everyone could access it and observe inner channel data that affects the privacy.
Solution
Add an optional authentication layer in front of the /metrics endpoint so a scraper must present a valid credential before any metrics are returned. When no credential is configured, the plugin should either keep current behavior for backwards compatibility or fail closed — that decision is worth calling out explicitly below.
- HTTP authentication on
/metrics. Support at least one of the standard schemes that both Prometheus and Grafana Alloy natively understand on the scrape side:
- Bearer token - plugin is configured with a token; requests must send
Authorization: Bearer <token>. Matches Prometheus/Alloy authorization scrape config.
- HTTP Basic auth - plugin is configured with a username/password; matches Prometheus/Alloy
basic_auth.
- Configuration via plugin options. Expose the credential through the normal CLN plugin option mechanism (e.g.
metrics-auth-token / metrics-basic-user + metrics-basic-pass), and support reading the secret from a file or environment variable rather than a plaintext CLI arg, so it doesn't leak into ps/logs.
- Constant-time comparison of the presented credential against the configured one to avoid timing side-channels.
- Correct HTTP semantics. Return 401 Unauthorized (with
WWW-Authenticate for Basic) on missing/invalid credentials; 200 only on success. Never leak metric data in the body of a failed request.
Open decision to resolve in the issue: should an unconfigured endpoint stay open (backwards compatible, log a warning) or fail closed (secure by default, but breaks existing setups on upgrade)? Recommend fail-closed with a clear migration note, or an explicit metrics-auth-disabled=true opt-out.
Acceptance criteria
[] A request to /metrics without valid credentials returns 401 and no metric data in the body.
[] A request to /metrics with valid credentials returns 200 and the expected metrics.
[] The credential (token or basic user/pass) is configurable through plugin options, and can be supplied via file/env var rather than only a plaintext CLI argument.
[] 401 responses include a WWW-Authenticate header when Basic auth is in use.
[] The behavior when no credential is configured is explicitly defined and documented (fail-closed with opt-out, per decision above), and that path is covered by a test.
[] The secret does not appear in process listings (ps) or plugin logs.
[] Automated tests cover: valid credential -> 200, missing credential -> 401, wrong credential -> 401.
[] Existing metric collection/format is unchanged for authenticated scrapes (no regression).
Problem
metrics-pluginexposes/metricsendpoint in order for scraping services (e.g. Prometheus or Grafana Alloy) to collect CLN metrics. Currently,/metricsis open - if the port is configured to be open for the whole world, potentially everyone could access it and observe inner channel data that affects the privacy.Solution
Add an optional authentication layer in front of the /metrics endpoint so a scraper must present a valid credential before any metrics are returned. When no credential is configured, the plugin should either keep current behavior for backwards compatibility or fail closed — that decision is worth calling out explicitly below.
/metrics. Support at least one of the standard schemes that both Prometheus and Grafana Alloy natively understand on the scrape side:Authorization: Bearer <token>. Matches Prometheus/Alloy authorization scrape config.basic_auth.metrics-auth-token/metrics-basic-user+metrics-basic-pass), and support reading the secret from a file or environment variable rather than a plaintext CLI arg, so it doesn't leak into ps/logs.WWW-AuthenticateforBasic) on missing/invalid credentials; 200 only on success. Never leak metric data in the body of a failed request.Open decision to resolve in the issue: should an unconfigured endpoint stay open (backwards compatible, log a warning) or fail closed (secure by default, but breaks existing setups on upgrade)? Recommend fail-closed with a clear migration note, or an explicit
metrics-auth-disabled=true opt-out.Acceptance criteria
[] A request to
/metricswithout valid credentials returns 401 and no metric data in the body.[] A request to
/metricswith valid credentials returns 200 and the expected metrics.[] The credential (token or basic user/pass) is configurable through plugin options, and can be supplied via file/env var rather than only a plaintext CLI argument.
[] 401 responses include a
WWW-Authenticate headerwhenBasicauth is in use.[] The behavior when no credential is configured is explicitly defined and documented (fail-closed with opt-out, per decision above), and that path is covered by a test.
[] The secret does not appear in process listings (ps) or plugin logs.
[] Automated tests cover: valid credential -> 200, missing credential -> 401, wrong credential -> 401.
[] Existing metric collection/format is unchanged for authenticated scrapes (no regression).