store basic auth credentials as hash instead of raw value
Update how the basic auth credentials are stored in the application to use a hashed value instead of the raw value. This prevents the raw value from being accidentally leaked. Add new `auth` package for functions related to authentication.
This commit is contained in:
parent
e176a3ea22
commit
26f0b0d0ce
14
src/auth/hash.go
Normal file
14
src/auth/hash.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Hash(data []byte) []byte {
|
||||||
|
b := sha256.Sum256(data)
|
||||||
|
return b[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func HashString(data string) string {
|
||||||
|
return string(Hash([]byte(data)))
|
||||||
|
}
|
30
src/auth/middleware.go
Normal file
30
src/auth/middleware.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fail2ban-prometheus-exporter/cfg"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BasicAuthMiddleware(handlerFunc http.HandlerFunc, appSettings *cfg.AppSettings) http.HandlerFunc {
|
||||||
|
authEnabled := len(appSettings.BasicAuthUsername) > 0 && len(appSettings.BasicAuthPassword) > 0
|
||||||
|
if authEnabled {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if doesBasicAuthMatch(r, appSettings) {
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
} else {
|
||||||
|
handlerFunc.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handlerFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func doesBasicAuthMatch(r *http.Request, appSettings *cfg.AppSettings) bool {
|
||||||
|
rawUsername, rawPassword, ok := r.BasicAuth()
|
||||||
|
if ok {
|
||||||
|
username := HashString(rawUsername)
|
||||||
|
password := HashString(rawPassword)
|
||||||
|
return username == appSettings.BasicAuthUsername && password == appSettings.BasicAuthPassword
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package cfg
|
package cfg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fail2ban-prometheus-exporter/auth"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@ -23,6 +24,9 @@ type AppSettings struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Parse() *AppSettings {
|
func Parse() *AppSettings {
|
||||||
|
var rawBasicAuthUsername string
|
||||||
|
var rawBasicAuthPassword string
|
||||||
|
|
||||||
appSettings := &AppSettings{}
|
appSettings := &AppSettings{}
|
||||||
flag.BoolVar(&appSettings.VersionMode, "version", false, "show version info and exit")
|
flag.BoolVar(&appSettings.VersionMode, "version", false, "show version info and exit")
|
||||||
flag.StringVar(&appSettings.MetricsAddress, "web.listen-address", "0.0.0.0", "address to use for the metrics server")
|
flag.StringVar(&appSettings.MetricsAddress, "web.listen-address", "0.0.0.0", "address to use for the metrics server")
|
||||||
@ -30,14 +34,20 @@ func Parse() *AppSettings {
|
|||||||
flag.StringVar(&appSettings.Fail2BanSocketPath, "socket", "", "path to the fail2ban server socket")
|
flag.StringVar(&appSettings.Fail2BanSocketPath, "socket", "", "path to the fail2ban server socket")
|
||||||
flag.BoolVar(&appSettings.FileCollectorEnabled, "collector.textfile", false, "enable the textfile collector")
|
flag.BoolVar(&appSettings.FileCollectorEnabled, "collector.textfile", false, "enable the textfile collector")
|
||||||
flag.StringVar(&appSettings.FileCollectorPath, "collector.textfile.directory", "", "directory to read text files with metrics from")
|
flag.StringVar(&appSettings.FileCollectorPath, "collector.textfile.directory", "", "directory to read text files with metrics from")
|
||||||
flag.StringVar(&appSettings.BasicAuthUsername, "web.basic-auth.username", "", "username to use to protect endpoints with basic auth")
|
flag.StringVar(&rawBasicAuthUsername, "web.basic-auth.username", "", "username to use to protect endpoints with basic auth")
|
||||||
flag.StringVar(&appSettings.BasicAuthPassword, "web.basic-auth.password", "", "password to use to protect endpoints with basic auth")
|
flag.StringVar(&rawBasicAuthPassword, "web.basic-auth.password", "", "password to use to protect endpoints with basic auth")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
appSettings.setBasicAuthValues(rawBasicAuthUsername, rawBasicAuthPassword)
|
||||||
appSettings.validateFlags()
|
appSettings.validateFlags()
|
||||||
return appSettings
|
return appSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (settings *AppSettings) setBasicAuthValues(username, password string) {
|
||||||
|
settings.BasicAuthUsername = auth.HashString(username)
|
||||||
|
settings.BasicAuthPassword = auth.HashString(password)
|
||||||
|
}
|
||||||
|
|
||||||
func (settings *AppSettings) validateFlags() {
|
func (settings *AppSettings) validateFlags() {
|
||||||
var flagsValid = true
|
var flagsValid = true
|
||||||
if !settings.VersionMode {
|
if !settings.VersionMode {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fail2ban-prometheus-exporter/auth"
|
||||||
"fail2ban-prometheus-exporter/cfg"
|
"fail2ban-prometheus-exporter/cfg"
|
||||||
"fail2ban-prometheus-exporter/collector/f2b"
|
"fail2ban-prometheus-exporter/collector/f2b"
|
||||||
"fail2ban-prometheus-exporter/collector/textfile"
|
"fail2ban-prometheus-exporter/collector/textfile"
|
||||||
@ -48,21 +49,6 @@ func metricHandler(w http.ResponseWriter, r *http.Request, collector *textfile.C
|
|||||||
collector.WriteTextFileMetrics(w, r)
|
collector.WriteTextFileMetrics(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func authMiddleware(handlerFunc http.HandlerFunc, appSettings *cfg.AppSettings) http.HandlerFunc {
|
|
||||||
authEnabled := len(appSettings.BasicAuthUsername) > 0 && len(appSettings.BasicAuthPassword) > 0
|
|
||||||
if authEnabled {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
username, password, ok := r.BasicAuth()
|
|
||||||
if !ok || username != appSettings.BasicAuthUsername || password != appSettings.BasicAuthPassword {
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
handlerFunc.ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return handlerFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
appSettings := cfg.Parse()
|
appSettings := cfg.Parse()
|
||||||
if appSettings.VersionMode {
|
if appSettings.VersionMode {
|
||||||
@ -78,8 +64,8 @@ func main() {
|
|||||||
textFileCollector := textfile.NewCollector(appSettings)
|
textFileCollector := textfile.NewCollector(appSettings)
|
||||||
prometheus.MustRegister(textFileCollector)
|
prometheus.MustRegister(textFileCollector)
|
||||||
|
|
||||||
http.HandleFunc("/", authMiddleware(rootHtmlHandler, appSettings))
|
http.HandleFunc("/", auth.BasicAuthMiddleware(rootHtmlHandler, appSettings))
|
||||||
http.HandleFunc(metricsPath, authMiddleware(
|
http.HandleFunc(metricsPath, auth.BasicAuthMiddleware(
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
metricHandler(w, r, textFileCollector)
|
metricHandler(w, r, textFileCollector)
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user