github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/lib/server/server.go (about) 1 package server 2 3 import ( 4 "context" 5 "crypto/tls" 6 "fmt" 7 "net/http" 8 "path/filepath" 9 10 "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/filemonitor" 11 "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/profile" 12 "github.com/prometheus/client_golang/prometheus/promhttp" 13 "github.com/sirupsen/logrus" 14 ) 15 16 // Option applies a configuration option to the given config. 17 type Option func(s *serverConfig) 18 19 func GetListenAndServeFunc(options ...Option) (func() error, error) { 20 sc := defaultServerConfig() 21 sc.apply(options) 22 23 return sc.getListenAndServeFunc() 24 } 25 26 func WithTLS(tlsCertPath, tlsKeyPath, clientCAPath *string) Option { 27 return func(sc *serverConfig) { 28 sc.tlsCertPath = tlsCertPath 29 sc.tlsKeyPath = tlsKeyPath 30 sc.clientCAPath = clientCAPath 31 } 32 } 33 34 func WithLogger(logger *logrus.Logger) Option { 35 return func(sc *serverConfig) { 36 sc.logger = logger 37 } 38 } 39 40 func WithDebug(debug bool) Option { 41 return func(sc *serverConfig) { 42 sc.debug = debug 43 } 44 } 45 46 type serverConfig struct { 47 logger *logrus.Logger 48 tlsCertPath *string 49 tlsKeyPath *string 50 clientCAPath *string 51 debug bool 52 } 53 54 func (sc *serverConfig) apply(options []Option) { 55 for _, o := range options { 56 o(sc) 57 } 58 } 59 60 func defaultServerConfig() serverConfig { 61 return serverConfig{ 62 tlsCertPath: nil, 63 tlsKeyPath: nil, 64 clientCAPath: nil, 65 logger: nil, 66 debug: false, 67 } 68 } 69 func (sc *serverConfig) tlsEnabled() (bool, error) { 70 if *sc.tlsCertPath != "" && *sc.tlsKeyPath != "" { 71 return true, nil 72 } 73 if *sc.tlsCertPath != "" || *sc.tlsKeyPath != "" { 74 return false, fmt.Errorf("both --tls-key and --tls-crt must be provided for TLS to be enabled") 75 } 76 return false, nil 77 } 78 79 func (sc *serverConfig) getAddress(tlsEnabled bool) string { 80 if tlsEnabled { 81 return ":8443" 82 } 83 return ":8080" 84 } 85 86 func (sc serverConfig) getListenAndServeFunc() (func() error, error) { 87 tlsEnabled, err := sc.tlsEnabled() 88 if err != nil { 89 return nil, fmt.Errorf("both --tls-key and --tls-crt must be provided for TLS to be enabled") 90 } 91 92 mux := http.NewServeMux() 93 mux.Handle("/metrics", promhttp.Handler()) 94 mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { 95 w.WriteHeader(http.StatusOK) 96 }) 97 profile.RegisterHandlers(mux, profile.WithTLS(tlsEnabled || !sc.debug)) 98 99 s := http.Server{ 100 Handler: mux, 101 Addr: sc.getAddress(tlsEnabled), 102 } 103 104 if !tlsEnabled { 105 return s.ListenAndServe, nil 106 } 107 108 sc.logger.Info("TLS keys set, using https for metrics") 109 certStore, err := filemonitor.NewCertStore(*sc.tlsCertPath, *sc.tlsKeyPath) 110 if err != nil { 111 return nil, fmt.Errorf("certificate monitoring for metrics (https) failed: %v", err) 112 } 113 114 csw, err := filemonitor.NewWatch(sc.logger, []string{filepath.Dir(*sc.tlsCertPath), filepath.Dir(*sc.tlsKeyPath)}, certStore.HandleFilesystemUpdate) 115 if err != nil { 116 return nil, fmt.Errorf("error creating cert file watcher: %v", err) 117 } 118 csw.Run(context.Background()) 119 certPoolStore, err := filemonitor.NewCertPoolStore(*sc.clientCAPath) 120 if err != nil { 121 return nil, fmt.Errorf("certificate monitoring for client-ca failed: %v", err) 122 } 123 cpsw, err := filemonitor.NewWatch(sc.logger, []string{filepath.Dir(*sc.clientCAPath)}, certPoolStore.HandleCABundleUpdate) 124 if err != nil { 125 return nil, fmt.Errorf("error creating cert file watcher: %v", err) 126 } 127 cpsw.Run(context.Background()) 128 129 s.TLSConfig = &tls.Config{ 130 GetCertificate: func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) { 131 return certStore.GetCertificate(), nil 132 }, 133 GetConfigForClient: func(_ *tls.ClientHelloInfo) (*tls.Config, error) { 134 var certs []tls.Certificate 135 if cert := certStore.GetCertificate(); cert != nil { 136 certs = append(certs, *cert) 137 } 138 return &tls.Config{ 139 Certificates: certs, 140 ClientCAs: certPoolStore.GetCertPool(), 141 ClientAuth: tls.VerifyClientCertIfGiven, 142 }, nil 143 }, 144 } 145 return func() error { 146 return s.ListenAndServeTLS("", "") 147 }, nil 148 }