feat: add new Prometheus metrics and bearer token auth for /metrics

Add 6 new Prometheus metrics for richer observability:
- auth_attempts_by_country_total (counter by country)
- commands_executed_total (counter by shell via OnCommand callback)
- human_score (histogram of final detection scores)
- storage_login_attempts_total, storage_unique_ips, storage_sessions_total
  (gauges via custom collector querying GetDashboardStats on each scrape)

Add optional bearer token authentication for the /metrics endpoint via
web.metrics_token config option. Uses crypto/subtle.ConstantTimeCompare.
Empty token (default) means no auth for backwards compatibility.

Also adds "cisco" to pre-initialized session/command metric labels.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 15:54:29 +01:00
parent 9aecc7ce02
commit df860b3061
16 changed files with 301 additions and 23 deletions

View File

@@ -21,9 +21,10 @@ type Config struct {
}
type WebConfig struct {
Enabled bool `toml:"enabled"`
Enabled bool `toml:"enabled"`
ListenAddr string `toml:"listen_addr"`
MetricsEnabled *bool `toml:"metrics_enabled"`
MetricsEnabled *bool `toml:"metrics_enabled"`
MetricsToken string `toml:"metrics_token"`
}
type ShellConfig struct {

View File

@@ -282,6 +282,22 @@ password = "toor"
}
}
func TestLoadMetricsToken(t *testing.T) {
content := `
[web]
enabled = true
metrics_token = "my-secret-token"
`
path := writeTemp(t, content)
cfg, err := Load(path)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cfg.Web.MetricsToken != "my-secret-token" {
t.Errorf("metrics_token = %q, want %q", cfg.Web.MetricsToken, "my-secret-token")
}
}
func TestLoadMissingFile(t *testing.T) {
_, err := Load("/nonexistent/path/config.toml")
if err == nil {