diff --git a/cmd/descheduler/app/descheduler.go b/cmd/descheduler/app/descheduler.go index 8a5e29a26..10bcba1ea 100644 --- a/cmd/descheduler/app/descheduler.go +++ b/cmd/descheduler/app/descheduler.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "strconv" + "time" "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -30,6 +31,19 @@ import ( "github.com/karmada-io/karmada/pkg/version/sharedcommand" ) +const ( + // ReadHeaderTimeout is the amount of time allowed to read + // request headers. + // HTTP timeouts are necessary to expire inactive connections + // and failing to do so might make the application vulnerable + // to attacks like slowloris which work by sending data very slow, + // which in case of no timeout will keep the connection active + // eventually leading to a denial-of-service (DoS) attack. + // References: + // - https://en.wikipedia.org/wiki/Slowloris_(computer_security) + ReadHeaderTimeout = 32 * time.Second +) + // NewDeschedulerCommand creates a *cobra.Command object with default parameters func NewDeschedulerCommand(stopChan <-chan struct{}) *cobra.Command { opts := options.NewOptions() @@ -152,6 +166,13 @@ func serveHealthzAndMetrics(address string) { }) mux.Handle("/metrics", promhttp.Handler()) - - klog.Fatal(http.ListenAndServe(address, mux)) + httpServer := http.Server{ + Addr: address, + Handler: mux, + ReadHeaderTimeout: ReadHeaderTimeout, + } + if err := httpServer.ListenAndServe(); err != nil { + klog.Errorf("Failed to serve healthz and metrics: %v", err) + os.Exit(1) + } } diff --git a/cmd/scheduler-estimator/app/scheduler-estimator.go b/cmd/scheduler-estimator/app/scheduler-estimator.go index 76b2dcb87..c00cae3bf 100644 --- a/cmd/scheduler-estimator/app/scheduler-estimator.go +++ b/cmd/scheduler-estimator/app/scheduler-estimator.go @@ -5,7 +5,9 @@ import ( "fmt" "net" "net/http" + "os" "strconv" + "time" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/spf13/cobra" @@ -26,6 +28,19 @@ import ( "github.com/karmada-io/karmada/pkg/version/sharedcommand" ) +const ( + // ReadHeaderTimeout is the amount of time allowed to read + // request headers. + // HTTP timeouts are necessary to expire inactive connections + // and failing to do so might make the application vulnerable + // to attacks like slowloris which work by sending data very slow, + // which in case of no timeout will keep the connection active + // eventually leading to a denial-of-service (DoS) attack. + // References: + // - https://en.wikipedia.org/wiki/Slowloris_(computer_security) + ReadHeaderTimeout = 32 * time.Second +) + // NewSchedulerEstimatorCommand creates a *cobra.Command object with default parameters func NewSchedulerEstimatorCommand(ctx context.Context) *cobra.Command { opts := options.NewOptions() @@ -98,5 +113,13 @@ func serveHealthzAndMetrics(address string) { mux.Handle("/metrics", promhttp.Handler()) - klog.Fatal(http.ListenAndServe(address, mux)) + httpServer := http.Server{ + Addr: address, + Handler: mux, + ReadHeaderTimeout: ReadHeaderTimeout, + } + if err := httpServer.ListenAndServe(); err != nil { + klog.Errorf("Failed to serve healthz and metrics: %v", err) + os.Exit(1) + } } diff --git a/cmd/scheduler/app/scheduler.go b/cmd/scheduler/app/scheduler.go index 469e27ecb..38bc10340 100644 --- a/cmd/scheduler/app/scheduler.go +++ b/cmd/scheduler/app/scheduler.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "strconv" + "time" "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -32,6 +33,19 @@ import ( "github.com/karmada-io/karmada/pkg/version/sharedcommand" ) +const ( + // ReadHeaderTimeout is the amount of time allowed to read + // request headers. + // HTTP timeouts are necessary to expire inactive connections + // and failing to do so might make the application vulnerable + // to attacks like slowloris which work by sending data very slow, + // which in case of no timeout will keep the connection active + // eventually leading to a denial-of-service (DoS) attack. + // References: + // - https://en.wikipedia.org/wiki/Slowloris_(computer_security) + ReadHeaderTimeout = 32 * time.Second +) + // Option configures a framework.Registry. type Option func(runtime.Registry) error @@ -180,6 +194,13 @@ func serveHealthzAndMetrics(address string) { }) mux.Handle("/metrics", promhttp.Handler()) - - klog.Fatal(http.ListenAndServe(address, mux)) + httpServer := http.Server{ + Addr: address, + Handler: mux, + ReadHeaderTimeout: ReadHeaderTimeout, + } + if err := httpServer.ListenAndServe(); err != nil { + klog.Errorf("Failed to serve healthz and metrics: %v", err) + os.Exit(1) + } } diff --git a/pkg/sharedcli/profileflag/profileflag.go b/pkg/sharedcli/profileflag/profileflag.go index da2eb7fd8..894d63ed7 100644 --- a/pkg/sharedcli/profileflag/profileflag.go +++ b/pkg/sharedcli/profileflag/profileflag.go @@ -4,11 +4,25 @@ import ( "net/http" "net/http/pprof" "os" + "time" "github.com/spf13/pflag" "k8s.io/klog/v2" ) +const ( + // ReadHeaderTimeout is the amount of time allowed to read + // request headers. + // HTTP timeouts are necessary to expire inactive connections + // and failing to do so might make the application vulnerable + // to attacks like slowloris which work by sending data very slow, + // which in case of no timeout will keep the connection active + // eventually leading to a denial-of-service (DoS) attack. + // References: + // - https://en.wikipedia.org/wiki/Slowloris_(computer_security) + ReadHeaderTimeout = 32 * time.Second +) + // Options are options for pprof. type Options struct { // EnableProfile is the flag about whether to enable pprof profiling. @@ -39,7 +53,12 @@ func ListenAndServe(opts Options) { installHandlerForPProf(mux) klog.Infof("Starting profiling on port %s", opts.ProfilingBindAddress) go func() { - if err := http.ListenAndServe(opts.ProfilingBindAddress, mux); err != nil { + httpServer := http.Server{ + Addr: opts.ProfilingBindAddress, + Handler: mux, + ReadHeaderTimeout: ReadHeaderTimeout, + } + if err := httpServer.ListenAndServe(); err != nil { klog.Errorf("Failed to enable profiling: %v", err) os.Exit(1) }