From 3999580fe655bf4a91af3a87ec9efb1b6711b3a1 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 28 Feb 2021 11:29:53 +0100 Subject: [PATCH] Add basic auth for metrics endpoint --- config.yml.sample | 12 +++++++++--- docs/content/doc/setup/config.md | 33 +++++++++++++++++++++++++------- pkg/config/config.go | 24 +++++++++++++++++------ pkg/routes/metrics.go | 21 +++++++++++++++++--- 4 files changed, 71 insertions(+), 19 deletions(-) diff --git a/config.yml.sample b/config.yml.sample index 9851e4e7..8a7bc2c5 100644 --- a/config.yml.sample +++ b/config.yml.sample @@ -13,9 +13,6 @@ service: rootpath: # The max number of items which can be returned per page maxitemsperpage: 50 - # If set to true, enables a /metrics endpoint for prometheus to collect metrics about the system - # You'll need to use redis for this in order to enable common metrics over multiple nodes - enablemetrics: false # Enable the caldav endpoint, see the docs for more details enablecaldav: true # Set the motd message, available from the /info endpoint @@ -283,3 +280,12 @@ auth: clientid: # The client secret used to authenticate Vikunja at the OpenID Connect provider. clientsecret: + +# Prometheus metrics endpoint +metrics: + # If set to true, enables a /metrics endpoint for prometheus to collect metrics about Vikunja. + enabled: false + # If set to a non-empty value the /metrics endpoint will require this as a username via basic auth in combination with the password below. + username: + # If set to a non-empty value the /metrics endpoint will require this as a password via basic auth in combination with the username below. + password: diff --git a/docs/content/doc/setup/config.md b/docs/content/doc/setup/config.md index 85c561e3..50c88b1c 100644 --- a/docs/content/doc/setup/config.md +++ b/docs/content/doc/setup/config.md @@ -100,13 +100,6 @@ The max number of items which can be returned per page Default: `50` -### enablemetrics - -If set to true, enables a /metrics endpoint for prometheus to collect metrics about the system -You'll need to use redis for this in order to enable common metrics over multiple nodes - -Default: `false` - ### enablecaldav Enable the caldav endpoint, see the docs for more details @@ -623,3 +616,29 @@ Take a look at the [default config file](https://kolaente.dev/vikunja/api/src/br Default: `` +--- + +## metrics + +Prometheus metrics endpoint + + + +### enabled + +If set to true, enables a /metrics endpoint for prometheus to collect metrics about Vikunja. + +Default: `false` + +### username + +If set to a non-empty value the /metrics endpoint will require this as a username via basic auth in combination with the password below. + +Default: `` + +### password + +If set to a non-empty value the /metrics endpoint will require this as a password via basic auth in combination with the username below. + +Default: `` + diff --git a/pkg/config/config.go b/pkg/config/config.go index c837c164..002c11e8 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -36,12 +36,13 @@ type Key string // These constants hold all config value keys const ( // #nosec - ServiceJWTSecret Key = `service.JWTSecret` - ServiceInterface Key = `service.interface` - ServiceFrontendurl Key = `service.frontendurl` - ServiceEnableCaldav Key = `service.enablecaldav` - ServiceRootpath Key = `service.rootpath` - ServiceMaxItemsPerPage Key = `service.maxitemsperpage` + ServiceJWTSecret Key = `service.JWTSecret` + ServiceInterface Key = `service.interface` + ServiceFrontendurl Key = `service.frontendurl` + ServiceEnableCaldav Key = `service.enablecaldav` + ServiceRootpath Key = `service.rootpath` + ServiceMaxItemsPerPage Key = `service.maxitemsperpage` + // Deprecated. Use metrics.enabled ServiceEnableMetrics Key = `service.enablemetrics` ServiceMotd Key = `service.motd` ServiceEnableLinkSharing Key = `service.enablelinksharing` @@ -142,6 +143,10 @@ const ( BackgroundsUnsplashApplicationID Key = `backgrounds.providers.unsplash.applicationid` KeyvalueType Key = `keyvalue.type` + + MetricsEnabled Key = `metrics.enabled` + MetricsUsername Key = `metrics.username` + MetricsPassword Key = `metrics.password` ) // GetString returns a string config value @@ -311,6 +316,8 @@ func InitDefaultConfig() { BackgroundsUnsplashEnabled.setDefault(false) // Key Value KeyvalueType.setDefault("memory") + // Metrics + MetricsEnabled.setDefault(false) } // InitConfig initializes the config, sets defaults etc. @@ -364,6 +371,11 @@ func InitConfig() { MigrationMicrosoftTodoRedirectURL.Set(ServiceFrontendurl.GetString() + "migrate/microsoft-todo") } + if ServiceEnableMetrics.GetBool() { + log.Println("WARNING: service.enablemetrics is deprecated and will be removed in a future release. Please use metrics.enable.") + MetricsEnabled.Set(true) + } + log.Printf("Using config file: %s", viper.ConfigFileUsed()) } diff --git a/pkg/routes/metrics.go b/pkg/routes/metrics.go index 7c471bed..b9995bbe 100644 --- a/pkg/routes/metrics.go +++ b/pkg/routes/metrics.go @@ -17,6 +17,8 @@ package routes import ( + "crypto/subtle" + "code.vikunja.io/api/pkg/config" "code.vikunja.io/api/pkg/log" "code.vikunja.io/api/pkg/metrics" @@ -24,11 +26,12 @@ import ( auth2 "code.vikunja.io/api/pkg/modules/auth" "code.vikunja.io/api/pkg/user" "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" "github.com/prometheus/client_golang/prometheus/promhttp" ) func setupMetrics(a *echo.Group) { - if !config.ServiceEnableMetrics.GetBool() { + if !config.MetricsEnabled.GetBool() { return } @@ -71,11 +74,23 @@ func setupMetrics(a *echo.Group) { } } - a.GET("/metrics", echo.WrapHandler(promhttp.HandlerFor(metrics.GetRegistry(), promhttp.HandlerOpts{}))) + r := a.Group("/metrics") + + if config.MetricsUsername.GetString() != "" && config.MetricsPassword.GetString() != "" { + r.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) { + if subtle.ConstantTimeCompare([]byte(username), []byte(config.MetricsUsername.GetString())) == 1 && + subtle.ConstantTimeCompare([]byte(password), []byte(config.MetricsPassword.GetString())) == 1 { + return true, nil + } + return false, nil + })) + } + + r.GET("", echo.WrapHandler(promhttp.HandlerFor(metrics.GetRegistry(), promhttp.HandlerOpts{}))) } func setupMetricsMiddleware(a *echo.Group) { - if !config.ServiceEnableMetrics.GetBool() { + if !config.MetricsEnabled.GetBool() { return }