diff --git a/cmd/cadvisor.go b/cmd/cadvisor.go index 04ccaeefc75..705cc909438 100644 --- a/cmd/cadvisor.go +++ b/cmd/cadvisor.go @@ -16,8 +16,10 @@ package main import ( "crypto/tls" + "crypto/x509" "flag" "fmt" + "net" "net/http" "net/http/pprof" "os" @@ -55,6 +57,11 @@ var httpAuthRealm = flag.String("http_auth_realm", "localhost", "HTTP auth realm var httpDigestFile = flag.String("http_digest_file", "", "HTTP digest file for the web UI") var httpDigestRealm = flag.String("http_digest_realm", "localhost", "HTTP digest file for the web UI") +var tlsCertPath = flag.String("tls_cert_path", "", "TLS certificate file path") +var tlsKeyPath = flag.String("tls_key_path", "", "TLS key file path") +var tlsCAPath = flag.String("tls_ca_path", "", "TLS certificate authority file path") +var tlsClientAuth = flag.String("tls_client_auth", "require", "TLS authentication mode, must be one of request, optional, requireany, require or none") + var prometheusEndpoint = flag.String("prometheus_endpoint", "/metrics", "Endpoint to expose Prometheus metrics on") var enableProfiling = flag.Bool("profiling", false, "Enable profiling via web interface host:port/debug/pprof/") @@ -153,6 +160,53 @@ func main() { klog.Fatalf("Failed to register HTTP handlers: %v", err) } + // Load TLS server configuration + var tlsConfig tls.Config + if *tlsCertPath != "" && *tlsKeyPath != "" { + if *tlsCertPath == "" || *tlsKeyPath == "" { + klog.Fatal("Both tls_cert_path and tls_key_path are required at the same time") + } + + // Verify that the key/certificate load and are valid before starting up + _, err := tls.LoadX509KeyPair(*tlsCertPath, *tlsKeyPath) + if err != nil { + klog.Fatalf("Failed to load TLS certificate/key pair: %v", err) + } + + tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + cert, err := tls.LoadX509KeyPair(*tlsCertPath, *tlsKeyPath) + if err != nil { + return nil, err + } + return &cert, nil + } + } + + if *tlsCAPath != "" { + clientCAPool := x509.NewCertPool() + clientCAFile, err := os.ReadFile(*tlsCAPath) + if err != nil { + klog.Fatalf("Failed to load TLS CA file: %v", err) + } + clientCAPool.AppendCertsFromPEM(clientCAFile) + tlsConfig.ClientCAs = clientCAPool + } + + switch *tlsClientAuth { + case "request": + tlsConfig.ClientAuth = tls.RequestClientCert + case "optional": + tlsConfig.ClientAuth = tls.VerifyClientCertIfGiven + case "requireany": + tlsConfig.ClientAuth = tls.RequireAnyClientCert + case "require": + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert + case "none": + tlsConfig.ClientAuth = tls.NoClientCert + default: + klog.Fatalf("Invalid tls_client_auth: %s", *tlsClientAuth) + } + containerLabelFunc := metrics.DefaultContainerLabels if !*storeContainerLabels { whitelistedLabels := strings.Split(*whitelistedContainerLabels, ",") @@ -176,7 +230,23 @@ func main() { rootMux.Handle(*urlBasePrefix+"/", http.StripPrefix(*urlBasePrefix, mux)) addr := fmt.Sprintf("%s:%d", *argIP, *argPort) - klog.Fatal(http.ListenAndServe(addr, rootMux)) + listener, err := net.Listen("tcp", addr) + if err != nil { + klog.Fatal(err) + } + + // Wrap in a TLS listener if cert/key was specfied + if *tlsCertPath != "" { + listener = tls.NewListener(listener, &tlsConfig) + klog.V(1).Infof("Listening for TLS connections") + } + + server := &http.Server{ + Addr: addr, + Handler: rootMux, + TLSConfig: &tlsConfig, + } + klog.Fatal(server.Serve(listener)) } func setMaxProcs() {