mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-05-20 13:20:31 +00:00
324c2f4fed
pprof[1] is the Go standard library profiling toolkit. It is invaluable for diagnosing how Go programs perform in the wild. However it also is able to expose secret data set with command line flags. This is not ideal and should be mitigated by correctly configured firewall rules. We don't live in a world where people correctly configure firewall rules, so we have to fix things for people. Welcome to 2026. [1]: https://pkg.go.dev/runtime/pprof Ref: AWOO-001 Signed-off-by: Xe Iaso <me@xeiaso.net>
135 lines
3.3 KiB
Go
135 lines
3.3 KiB
Go
package metrics
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/pprof"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/TecharoHQ/anubis/internal"
|
|
"github.com/TecharoHQ/anubis/lib/config"
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
healthv1 "google.golang.org/grpc/health/grpc_health_v1"
|
|
)
|
|
|
|
type Server struct {
|
|
Config *config.Metrics
|
|
Log *slog.Logger
|
|
}
|
|
|
|
func (s *Server) Run(ctx context.Context, done func()) {
|
|
defer done()
|
|
lg := s.Log.With("subsystem", "metrics")
|
|
|
|
if err := s.run(ctx, lg); err != nil {
|
|
lg.Error("can't serve metrics server", "err", err)
|
|
}
|
|
}
|
|
|
|
func (s *Server) run(ctx context.Context, lg *slog.Logger) error {
|
|
mux := http.NewServeMux()
|
|
|
|
if s.Config.Debug {
|
|
mux.HandleFunc("GET /debug/pprof/", pprof.Index)
|
|
mux.HandleFunc("GET /debug/pprof/cmdline", pprof.Cmdline)
|
|
mux.HandleFunc("GET /debug/pprof/profile", pprof.Profile)
|
|
mux.HandleFunc("GET /debug/pprof/symbol", pprof.Symbol)
|
|
mux.HandleFunc("GET /debug/pprof/trace", pprof.Trace)
|
|
}
|
|
|
|
mux.Handle("/metrics", promhttp.Handler())
|
|
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
|
|
st, ok := internal.GetHealth("anubis")
|
|
if !ok {
|
|
slog.Error("health service anubis does not exist, file a bug")
|
|
}
|
|
|
|
switch st {
|
|
case healthv1.HealthCheckResponse_NOT_SERVING:
|
|
http.Error(w, "NOT OK", http.StatusInternalServerError)
|
|
return
|
|
case healthv1.HealthCheckResponse_SERVING:
|
|
fmt.Fprintln(w, "OK")
|
|
return
|
|
default:
|
|
http.Error(w, "UNKNOWN", http.StatusFailedDependency)
|
|
return
|
|
}
|
|
})
|
|
|
|
srv := http.Server{
|
|
Handler: mux,
|
|
ErrorLog: internal.GetFilteredHTTPLogger(),
|
|
}
|
|
|
|
ln, metricsURL, err := internal.SetupListener(s.Config.Network, s.Config.Bind, s.Config.SocketMode)
|
|
if err != nil {
|
|
return fmt.Errorf("can't setup listener: %w", err)
|
|
}
|
|
|
|
defer ln.Close()
|
|
|
|
if s.Config.TLS != nil {
|
|
kpr, err := NewKeypairReloader(s.Config.TLS.Certificate, s.Config.TLS.Key, lg)
|
|
if err != nil {
|
|
return fmt.Errorf("can't setup keypair reloader: %w", err)
|
|
}
|
|
|
|
srv.TLSConfig = &tls.Config{
|
|
GetCertificate: kpr.GetCertificate,
|
|
}
|
|
|
|
if s.Config.TLS.CA != "" {
|
|
caCert, err := os.ReadFile(s.Config.TLS.CA)
|
|
if err != nil {
|
|
return fmt.Errorf("%w %s: %w", config.ErrCantReadFile, s.Config.TLS.CA, err)
|
|
}
|
|
|
|
certPool := x509.NewCertPool()
|
|
if !certPool.AppendCertsFromPEM(caCert) {
|
|
return fmt.Errorf("%w %s", config.ErrInvalidMetricsCACertificate, s.Config.TLS.CA)
|
|
}
|
|
|
|
srv.TLSConfig.ClientCAs = certPool
|
|
srv.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
|
}
|
|
}
|
|
|
|
if s.Config.BasicAuth != nil {
|
|
var h http.Handler = mux
|
|
h = internal.BasicAuth("anubis-metrics", s.Config.BasicAuth.Username, s.Config.BasicAuth.Password, mux)
|
|
|
|
srv.Handler = h
|
|
}
|
|
|
|
lg.Debug("listening for metrics", "url", metricsURL)
|
|
|
|
go func() {
|
|
<-ctx.Done()
|
|
c, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
if err := srv.Shutdown(c); err != nil {
|
|
lg.Error("can't shut down metrics server", "err", err)
|
|
}
|
|
}()
|
|
|
|
switch s.Config.TLS != nil {
|
|
case true:
|
|
if err := srv.ServeTLS(ln, "", ""); !errors.Is(err, http.ErrServerClosed) {
|
|
return fmt.Errorf("can't serve TLS metrics server: %w", err)
|
|
}
|
|
case false:
|
|
if err := srv.Serve(ln); !errors.Is(err, http.ErrServerClosed) {
|
|
return fmt.Errorf("can't serve metrics server: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|