mirror of
https://github.com/NotAShelf/watchdog.git
synced 2026-04-17 15:50:18 +00:00
watchdog: apply ratelimits to the metrics endpoint
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Ic0b5a3c978f7c6c4657fc5d794c72fe36a6a6964
This commit is contained in:
parent
fd3a832f7b
commit
ac24734e8f
1 changed files with 19 additions and 2 deletions
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
|
@ -21,6 +22,7 @@ import (
|
||||||
"notashelf.dev/watchdog/internal/health"
|
"notashelf.dev/watchdog/internal/health"
|
||||||
"notashelf.dev/watchdog/internal/limits"
|
"notashelf.dev/watchdog/internal/limits"
|
||||||
"notashelf.dev/watchdog/internal/normalize"
|
"notashelf.dev/watchdog/internal/normalize"
|
||||||
|
"notashelf.dev/watchdog/internal/ratelimit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Run(cfg *config.Config) error {
|
func Run(cfg *config.Config) error {
|
||||||
|
|
@ -75,7 +77,7 @@ func Run(cfg *config.Config) error {
|
||||||
// Setup routes
|
// Setup routes
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
// Metrics endpoint with optional basic auth
|
// Metrics endpoint with optional basic auth and rate limiting
|
||||||
metricsHandler := promhttp.HandlerFor(promRegistry, promhttp.HandlerOpts{
|
metricsHandler := promhttp.HandlerFor(promRegistry, promhttp.HandlerOpts{
|
||||||
EnableOpenMetrics: true,
|
EnableOpenMetrics: true,
|
||||||
})
|
})
|
||||||
|
|
@ -88,6 +90,10 @@ func Run(cfg *config.Config) error {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add rate limiting to metrics endpoint (30 requests per minute)
|
||||||
|
metricsRateLimiter := ratelimit.NewTokenBucket(30, 30, time.Minute)
|
||||||
|
metricsHandler = rateLimitMiddleware(metricsHandler, metricsRateLimiter)
|
||||||
|
|
||||||
mux.Handle(cfg.Server.MetricsPath, metricsHandler)
|
mux.Handle(cfg.Server.MetricsPath, metricsHandler)
|
||||||
|
|
||||||
// Ingestion endpoint
|
// Ingestion endpoint
|
||||||
|
|
@ -168,7 +174,18 @@ func basicAuth(next http.Handler, username, password string) http.Handler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanitizes a path for logging to prevent log injection attacks. Uses strconv.Quote
|
// Wraps a handler with rate limiting
|
||||||
|
func rateLimitMiddleware(next http.Handler, limiter *ratelimit.TokenBucket) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !limiter.Allow() {
|
||||||
|
http.Error(w, "Rate limit exceeded", http.StatusTooManyRequests)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanitizes a path for logging to prevent log injection attacks. Uses `strconv.Quote`
|
||||||
// to properly escape control characters and special bytes.
|
// to properly escape control characters and special bytes.
|
||||||
func sanitizePathForLog(path string) string {
|
func sanitizePathForLog(path string) string {
|
||||||
escaped := strconv.Quote(path)
|
escaped := strconv.Quote(path)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue