Skip to content

Commit ff760a1

Browse files
authored
Expose pprof endpoint if tls is not configured (#2422)
* Expose pprof endpoint when debugging This commit introduces a change that allows requests to the pprof endpoint to be made without a client certificate when OLM is not configured to use certificates and is ran with the --debug flag. * Address feedback
1 parent 74e0a4c commit ff760a1

File tree

4 files changed

+152
-81
lines changed

4 files changed

+152
-81
lines changed

cmd/catalog/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func main() {
109109
*catalogNamespace = catalogNamespaceEnvVarValue
110110
}
111111

112-
listenAndServe, err := server.GetListenAndServeFunc(logger, tlsCertPath, tlsKeyPath, clientCAPath)
112+
listenAndServe, err := server.GetListenAndServeFunc(server.WithLogger(logger), server.WithTLS(tlsCertPath, tlsKeyPath, clientCAPath), server.WithDebug(*debug))
113113
if err != nil {
114114
logger.Fatal("Error setting up health/metric/pprof service: %v", err)
115115
}

cmd/olm/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ func main() {
118118
}
119119
logger.Infof("log level %s", logger.Level)
120120

121-
listenAndServe, err := server.GetListenAndServeFunc(logger, tlsCertPath, tlsKeyPath, clientCAPath)
121+
listenAndServe, err := server.GetListenAndServeFunc(server.WithLogger(logger), server.WithTLS(tlsCertPath, tlsKeyPath, clientCAPath), server.WithDebug(*debug))
122122
if err != nil {
123123
logger.Fatal("Error setting up health/metric/pprof service: %v", err)
124124
}

pkg/lib/profile/profile.go

+27-24
Original file line numberDiff line numberDiff line change
@@ -6,36 +6,39 @@ import (
66
)
77

88
type profileConfig struct {
9-
pprof bool
10-
cmdline bool
11-
profile bool
12-
symbol bool
13-
trace bool
9+
pprof bool
10+
cmdline bool
11+
profile bool
12+
symbol bool
13+
trace bool
14+
enableTLS bool
1415
}
1516

1617
// Option applies a configuration option to the given config.
1718
type Option func(p *profileConfig)
1819

1920
func (p *profileConfig) apply(options []Option) {
20-
if len(options) == 0 {
21-
// If no options are given, default to all
22-
p.pprof = true
23-
p.cmdline = true
24-
p.profile = true
25-
p.symbol = true
26-
p.trace = true
27-
28-
return
29-
}
30-
3121
for _, o := range options {
3222
o(p)
3323
}
3424
}
3525

26+
func WithTLS(enabled bool) Option {
27+
return func(p *profileConfig) {
28+
p.enableTLS = enabled
29+
}
30+
}
31+
3632
func defaultProfileConfig() *profileConfig {
3733
// Initialize config
38-
return &profileConfig{}
34+
return &profileConfig{
35+
pprof: true,
36+
cmdline: true,
37+
profile: true,
38+
symbol: true,
39+
trace: true,
40+
enableTLS: true,
41+
}
3942
}
4043

4144
// RegisterHandlers registers profile Handlers with the given ServeMux.
@@ -47,25 +50,25 @@ func RegisterHandlers(mux *http.ServeMux, options ...Option) {
4750
config.apply(options)
4851

4952
if config.pprof {
50-
mux.Handle("/debug/pprof/", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Index)))
53+
mux.Handle("/debug/pprof/", pprofHandlerFunc(http.HandlerFunc(pprof.Index), config.enableTLS))
5154
}
5255
if config.cmdline {
53-
mux.Handle("/debug/pprof/cmdline", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Cmdline)))
56+
mux.Handle("/debug/pprof/cmdline", pprofHandlerFunc(http.HandlerFunc(pprof.Cmdline), config.enableTLS))
5457
}
5558
if config.profile {
56-
mux.Handle("/debug/pprof/profile", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Profile)))
59+
mux.Handle("/debug/pprof/profile", pprofHandlerFunc(http.HandlerFunc(pprof.Profile), config.enableTLS))
5760
}
5861
if config.symbol {
59-
mux.Handle("/debug/pprof/symbol", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Symbol)))
62+
mux.Handle("/debug/pprof/symbol", pprofHandlerFunc(http.HandlerFunc(pprof.Symbol), config.enableTLS))
6063
}
6164
if config.trace {
62-
mux.Handle("/debug/pprof/trace", requireVerifiedClientCertificate(http.HandlerFunc(pprof.Trace)))
65+
mux.Handle("/debug/pprof/trace", pprofHandlerFunc(http.HandlerFunc(pprof.Trace), config.enableTLS))
6366
}
6467
}
6568

66-
func requireVerifiedClientCertificate(h http.Handler) http.Handler {
69+
func pprofHandlerFunc(h http.Handler, enableTLS bool) http.Handler {
6770
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
68-
if r.TLS == nil || len(r.TLS.VerifiedChains) == 0 {
71+
if enableTLS && (r.TLS == nil || len(r.TLS.VerifiedChains) == 0) {
6972
w.WriteHeader(http.StatusForbidden)
7073
return
7174
}

pkg/lib/server/server.go

+123-55
Original file line numberDiff line numberDiff line change
@@ -13,68 +13,136 @@ import (
1313
"github.com/sirupsen/logrus"
1414
)
1515

16-
func GetListenAndServeFunc(logger *logrus.Logger, tlsCertPath, tlsKeyPath, clientCAPath *string) (func() error, error) {
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+
1792
mux := http.NewServeMux()
18-
profile.RegisterHandlers(mux)
1993
mux.Handle("/metrics", promhttp.Handler())
2094
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
2195
w.WriteHeader(http.StatusOK)
2296
})
97+
profile.RegisterHandlers(mux, profile.WithTLS(tlsEnabled || !sc.debug))
2398

2499
s := http.Server{
25100
Handler: mux,
26-
Addr: ":8080",
27-
}
28-
listenAndServe := s.ListenAndServe
29-
30-
if *tlsCertPath != "" && *tlsKeyPath != "" {
31-
logger.Info("TLS keys set, using https for metrics")
32-
33-
certStore, err := filemonitor.NewCertStore(*tlsCertPath, *tlsKeyPath)
34-
if err != nil {
35-
return nil, fmt.Errorf("certificate monitoring for metrics (https) failed: %v", err)
36-
}
37-
38-
csw, err := filemonitor.NewWatch(logger, []string{filepath.Dir(*tlsCertPath), filepath.Dir(*tlsKeyPath)}, certStore.HandleFilesystemUpdate)
39-
if err != nil {
40-
return nil, fmt.Errorf("error creating cert file watcher: %v", err)
41-
}
42-
csw.Run(context.Background())
43-
certPoolStore, err := filemonitor.NewCertPoolStore(*clientCAPath)
44-
if err != nil {
45-
return nil, fmt.Errorf("certificate monitoring for client-ca failed: %v", err)
46-
}
47-
cpsw, err := filemonitor.NewWatch(logger, []string{filepath.Dir(*clientCAPath)}, certPoolStore.HandleCABundleUpdate)
48-
if err != nil {
49-
return nil, fmt.Errorf("error creating cert file watcher: %v", err)
50-
}
51-
cpsw.Run(context.Background())
52-
53-
s.Addr = ":8443"
54-
s.TLSConfig = &tls.Config{
55-
GetCertificate: func(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
56-
return certStore.GetCertificate(), nil
57-
},
58-
GetConfigForClient: func(_ *tls.ClientHelloInfo) (*tls.Config, error) {
59-
var certs []tls.Certificate
60-
if cert := certStore.GetCertificate(); cert != nil {
61-
certs = append(certs, *cert)
62-
}
63-
return &tls.Config{
64-
Certificates: certs,
65-
ClientCAs: certPoolStore.GetCertPool(),
66-
ClientAuth: tls.VerifyClientCertIfGiven,
67-
}, nil
68-
},
69-
}
70-
71-
listenAndServe = func() error {
72-
return s.ListenAndServeTLS("", "")
73-
}
74-
} else if *tlsCertPath != "" || *tlsKeyPath != "" {
75-
return nil, fmt.Errorf("both --tls-key and --tls-crt must be provided for TLS to be enabled")
76-
} else {
77-
logger.Info("TLS keys not set, using non-https for metrics")
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+
},
78144
}
79-
return listenAndServe, nil
145+
return func() error {
146+
return s.ListenAndServeTLS("", "")
147+
}, nil
80148
}

0 commit comments

Comments
 (0)