Blockstream / Blockstream/cln-plugins
metrics-plugin: add authorization for `/metrics` endpoint
- Dominant language
- Rust
- Stars
- 3
- Forks
- 0
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 2
Description
# 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 `. 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).
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at the metrics-plugin /metrics handler and the normal CLN plugin option mechanism. Trace how metrics responses are currently served, then resolve and document the no-credential behavior before covering valid, missing, and invalid credentials in automated tests. Done means authenticated scrapes retain the existing metrics format and failed requests return no metric data.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- grafana, prometheus, rust
- Domain
- backend-api-design, observability-sre, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100