Add basic auth for metrics endpoint

This commit is contained in:
kolaente 2021-02-28 11:29:53 +01:00
parent c71a1fea82
commit 3999580fe6
Signed by untrusted user: konrad
GPG Key ID: F40E70337AB24C9B
4 changed files with 71 additions and 19 deletions

View File

@ -13,9 +13,6 @@ service:
rootpath: <rootpath> rootpath: <rootpath>
# The max number of items which can be returned per page # The max number of items which can be returned per page
maxitemsperpage: 50 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 # Enable the caldav endpoint, see the docs for more details
enablecaldav: true enablecaldav: true
# Set the motd message, available from the /info endpoint # Set the motd message, available from the /info endpoint
@ -283,3 +280,12 @@ auth:
clientid: clientid:
# The client secret used to authenticate Vikunja at the OpenID Connect provider. # The client secret used to authenticate Vikunja at the OpenID Connect provider.
clientsecret: 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:

View File

@ -100,13 +100,6 @@ The max number of items which can be returned per page
Default: `50` 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 ### enablecaldav
Enable the caldav endpoint, see the docs for more details 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: `<empty>` Default: `<empty>`
---
## 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: `<empty>`
### 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: `<empty>`

View File

@ -36,12 +36,13 @@ type Key string
// These constants hold all config value keys // These constants hold all config value keys
const ( const (
// #nosec // #nosec
ServiceJWTSecret Key = `service.JWTSecret` ServiceJWTSecret Key = `service.JWTSecret`
ServiceInterface Key = `service.interface` ServiceInterface Key = `service.interface`
ServiceFrontendurl Key = `service.frontendurl` ServiceFrontendurl Key = `service.frontendurl`
ServiceEnableCaldav Key = `service.enablecaldav` ServiceEnableCaldav Key = `service.enablecaldav`
ServiceRootpath Key = `service.rootpath` ServiceRootpath Key = `service.rootpath`
ServiceMaxItemsPerPage Key = `service.maxitemsperpage` ServiceMaxItemsPerPage Key = `service.maxitemsperpage`
// Deprecated. Use metrics.enabled
ServiceEnableMetrics Key = `service.enablemetrics` ServiceEnableMetrics Key = `service.enablemetrics`
ServiceMotd Key = `service.motd` ServiceMotd Key = `service.motd`
ServiceEnableLinkSharing Key = `service.enablelinksharing` ServiceEnableLinkSharing Key = `service.enablelinksharing`
@ -142,6 +143,10 @@ const (
BackgroundsUnsplashApplicationID Key = `backgrounds.providers.unsplash.applicationid` BackgroundsUnsplashApplicationID Key = `backgrounds.providers.unsplash.applicationid`
KeyvalueType Key = `keyvalue.type` KeyvalueType Key = `keyvalue.type`
MetricsEnabled Key = `metrics.enabled`
MetricsUsername Key = `metrics.username`
MetricsPassword Key = `metrics.password`
) )
// GetString returns a string config value // GetString returns a string config value
@ -311,6 +316,8 @@ func InitDefaultConfig() {
BackgroundsUnsplashEnabled.setDefault(false) BackgroundsUnsplashEnabled.setDefault(false)
// Key Value // Key Value
KeyvalueType.setDefault("memory") KeyvalueType.setDefault("memory")
// Metrics
MetricsEnabled.setDefault(false)
} }
// InitConfig initializes the config, sets defaults etc. // InitConfig initializes the config, sets defaults etc.
@ -364,6 +371,11 @@ func InitConfig() {
MigrationMicrosoftTodoRedirectURL.Set(ServiceFrontendurl.GetString() + "migrate/microsoft-todo") 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()) log.Printf("Using config file: %s", viper.ConfigFileUsed())
} }

View File

@ -17,6 +17,8 @@
package routes package routes
import ( import (
"crypto/subtle"
"code.vikunja.io/api/pkg/config" "code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/log" "code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/metrics" "code.vikunja.io/api/pkg/metrics"
@ -24,11 +26,12 @@ import (
auth2 "code.vikunja.io/api/pkg/modules/auth" auth2 "code.vikunja.io/api/pkg/modules/auth"
"code.vikunja.io/api/pkg/user" "code.vikunja.io/api/pkg/user"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
) )
func setupMetrics(a *echo.Group) { func setupMetrics(a *echo.Group) {
if !config.ServiceEnableMetrics.GetBool() { if !config.MetricsEnabled.GetBool() {
return 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) { func setupMetricsMiddleware(a *echo.Group) {
if !config.ServiceEnableMetrics.GetBool() { if !config.MetricsEnabled.GetBool() {
return return
} }