Add HTTP Basic authentication for /metrics endpoint
This commit is contained in:
parent
79ff381c4c
commit
877dbed5e8
4 changed files with 65 additions and 3 deletions
|
@ -72,6 +72,8 @@ const (
|
|||
defaultMetricsCollector = false
|
||||
defaultMetricsRefreshInterval = 60
|
||||
defaultMetricsAllowedNetworks = "127.0.0.1/8"
|
||||
defaultMetricsUsername = ""
|
||||
defaultMetricsPassword = ""
|
||||
defaultWatchdog = true
|
||||
defaultInvidiousInstance = "yewtu.be"
|
||||
)
|
||||
|
@ -144,6 +146,8 @@ type Options struct {
|
|||
metricsCollector bool
|
||||
metricsRefreshInterval int
|
||||
metricsAllowedNetworks []string
|
||||
metricsUsername string
|
||||
metricsPassword string
|
||||
watchdog bool
|
||||
invidiousInstance string
|
||||
proxyPrivateKey []byte
|
||||
|
@ -211,6 +215,8 @@ func NewOptions() *Options {
|
|||
metricsCollector: defaultMetricsCollector,
|
||||
metricsRefreshInterval: defaultMetricsRefreshInterval,
|
||||
metricsAllowedNetworks: []string{defaultMetricsAllowedNetworks},
|
||||
metricsUsername: defaultMetricsUsername,
|
||||
metricsPassword: defaultMetricsPassword,
|
||||
watchdog: defaultWatchdog,
|
||||
invidiousInstance: defaultInvidiousInstance,
|
||||
proxyPrivateKey: randomKey,
|
||||
|
@ -513,6 +519,14 @@ func (o *Options) MetricsAllowedNetworks() []string {
|
|||
return o.metricsAllowedNetworks
|
||||
}
|
||||
|
||||
func (o *Options) MetricsUsername() string {
|
||||
return o.metricsUsername
|
||||
}
|
||||
|
||||
func (o *Options) MetricsPassword() string {
|
||||
return o.metricsPassword
|
||||
}
|
||||
|
||||
// HTTPClientUserAgent returns the global User-Agent header for miniflux.
|
||||
func (o *Options) HTTPClientUserAgent() string {
|
||||
return o.httpClientUserAgent
|
||||
|
@ -576,6 +590,8 @@ func (o *Options) SortedOptions(redactSecret bool) []*Option {
|
|||
"METRICS_ALLOWED_NETWORKS": strings.Join(o.metricsAllowedNetworks, ","),
|
||||
"METRICS_COLLECTOR": o.metricsCollector,
|
||||
"METRICS_REFRESH_INTERVAL": o.metricsRefreshInterval,
|
||||
"METRICS_USERNAME": o.metricsUsername,
|
||||
"METRICS_PASSWORD": redactSecretValue(o.metricsPassword, redactSecret),
|
||||
"OAUTH2_CLIENT_ID": o.oauth2ClientID,
|
||||
"OAUTH2_CLIENT_SECRET": redactSecretValue(o.oauth2ClientSecret, redactSecret),
|
||||
"OAUTH2_OIDC_DISCOVERY_ENDPOINT": o.oauth2OidcDiscoveryEndpoint,
|
||||
|
@ -626,7 +642,7 @@ func (o *Options) String() string {
|
|||
|
||||
func redactSecretValue(value string, redactSecret bool) string {
|
||||
if redactSecret && value != "" {
|
||||
return "******"
|
||||
return "<secret>"
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
|
|
@ -207,6 +207,14 @@ func (p *Parser) parseLines(lines []string) (err error) {
|
|||
p.opts.metricsRefreshInterval = parseInt(value, defaultMetricsRefreshInterval)
|
||||
case "METRICS_ALLOWED_NETWORKS":
|
||||
p.opts.metricsAllowedNetworks = parseStringList(value, []string{defaultMetricsAllowedNetworks})
|
||||
case "METRICS_USERNAME":
|
||||
p.opts.metricsUsername = parseString(value, defaultMetricsUsername)
|
||||
case "METRICS_USERNAME_FILE":
|
||||
p.opts.metricsUsername = readSecretFile(value, defaultMetricsUsername)
|
||||
case "METRICS_PASSWORD":
|
||||
p.opts.metricsPassword = parseString(value, defaultMetricsPassword)
|
||||
case "METRICS_PASSWORD_FILE":
|
||||
p.opts.metricsPassword = readSecretFile(value, defaultMetricsPassword)
|
||||
case "FETCH_YOUTUBE_WATCH_TIME":
|
||||
p.opts.fetchYouTubeWatchTime = parseBool(value, defaultFetchYouTubeWatchTime)
|
||||
case "WATCHDOG":
|
||||
|
|
20
miniflux.1
20
miniflux.1
|
@ -283,6 +283,26 @@ List of networks allowed to access the metrics endpoint (comma-separated values)
|
|||
.br
|
||||
Default is 127.0.0.1/8\&.
|
||||
.TP
|
||||
.B METRICS_USERNAME
|
||||
Metrics endpoint username for basic HTTP authentication\&.
|
||||
.br
|
||||
Default is emtpty\&.
|
||||
.TP
|
||||
.B METRICS_USERNAME_FILE
|
||||
Path to a file that contains the username for the metrics endpoint HTTP authentication\&.
|
||||
.br
|
||||
Default is emtpty\&.
|
||||
.TP
|
||||
.B METRICS_PASSWORD
|
||||
Metrics endpoint password for basic HTTP authentication\&.
|
||||
.br
|
||||
Default is emtpty\&.
|
||||
.TP
|
||||
.B METRICS_PASSWORD_FILE
|
||||
Path to a file that contains the password for the metrics endpoint HTTP authentication\&.
|
||||
.br
|
||||
Default is emtpty\&.
|
||||
.TP
|
||||
.B OAUTH2_PROVIDER
|
||||
Possible values are "google" or "oidc"\&.
|
||||
.br
|
||||
|
|
|
@ -222,7 +222,25 @@ func setupHandler(store *storage.Storage, pool *worker.Pool) *mux.Router {
|
|||
}
|
||||
|
||||
func isAllowedToAccessMetricsEndpoint(r *http.Request) bool {
|
||||
clientIP := net.ParseIP(request.ClientIP(r))
|
||||
clientIP := request.ClientIP(r)
|
||||
|
||||
if config.Opts.MetricsUsername() != "" && config.Opts.MetricsPassword() != "" {
|
||||
username, password, authOK := r.BasicAuth()
|
||||
if !authOK {
|
||||
logger.Info("[Metrics] [ClientIP=%s] No authentication header sent", clientIP)
|
||||
return false
|
||||
}
|
||||
|
||||
if username == "" || password == "" {
|
||||
logger.Info("[Metrics] [ClientIP=%s] Empty username or password", clientIP)
|
||||
return false
|
||||
}
|
||||
|
||||
if username != config.Opts.MetricsUsername() || password != config.Opts.MetricsPassword() {
|
||||
logger.Error("[Metrics] [ClientIP=%s] Invalid username or password", clientIP)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for _, cidr := range config.Opts.MetricsAllowedNetworks() {
|
||||
_, network, err := net.ParseCIDR(cidr)
|
||||
|
@ -230,7 +248,7 @@ func isAllowedToAccessMetricsEndpoint(r *http.Request) bool {
|
|||
logger.Fatal(`[Metrics] Unable to parse CIDR %v`, err)
|
||||
}
|
||||
|
||||
if network.Contains(clientIP) {
|
||||
if network.Contains(net.ParseIP(clientIP)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue