Skip to content

Commit dd0fc0d

Browse files
committed
🌱 Implement dynamic TLS configuration for HTTP client
Added a new dynamicTLSRoundtripper to allow for context-specific TLS configurations in HTTP requests. This prevents overwriting the global http.DefaultClient's TLS settings, addressing potential race conditions in concurrent calls. The httpClient now utilizes this new roundtripper to manage TLS settings effectively without creating a new http.Client every call and therefore still benefitting from http.Client optimization around connection reuse, etc.
1 parent 83efbb1 commit dd0fc0d

File tree

1 file changed

+34
-8
lines changed

1 file changed

+34
-8
lines changed

internal/runtime/client/client.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package client
2020
import (
2121
"bytes"
2222
"context"
23+
"crypto/tls"
2324
"encoding/json"
2425
"fmt"
2526
"io"
@@ -441,6 +442,37 @@ type httpCallOptions struct {
441442
timeout time.Duration
442443
}
443444

445+
type tlsConfigContextKeyType string
446+
447+
const tlsConfigContextKey = tlsConfigContextKeyType("tlsConfig")
448+
449+
type dynamicTLSRoundtripper struct {
450+
baseTransport *http.Transport
451+
}
452+
453+
func (d *dynamicTLSRoundtripper) RoundTrip(req *http.Request) (*http.Response, error) {
454+
// 1. Extract TLS config from context
455+
ctxConfig, ok := req.Context().Value(tlsConfigContextKey).(*tls.Config)
456+
457+
// If no specific config provided, use the base transport
458+
if !ok {
459+
return d.baseTransport.RoundTrip(req)
460+
}
461+
462+
// We clone the baseTransport to keep settings like Proxy, DialContext, etc.
463+
newTransport := d.baseTransport.Clone()
464+
newTransport.TLSClientConfig = ctxConfig
465+
466+
return newTransport.RoundTrip(req)
467+
}
468+
469+
var httpClient = &http.Client{
470+
Transport: &dynamicTLSRoundtripper{
471+
// This also adds http2
472+
baseTransport: utilnet.SetTransportDefaults(&http.Transport{}),
473+
},
474+
}
475+
444476
func httpCall(ctx context.Context, request, response runtime.Object, opts *httpCallOptions) error {
445477
log := ctrl.LoggerFrom(ctx)
446478
if opts == nil || request == nil || response == nil {
@@ -518,9 +550,6 @@ func httpCall(ctx context.Context, request, response runtime.Object, opts *httpC
518550
}
519551

520552
// Use client-go's transport.TLSConfigureFor to ensure good defaults for tls
521-
client := &http.Client{}
522-
defer client.CloseIdleConnections()
523-
524553
tlsConfig, err := transport.TLSConfigFor(&transport.Config{
525554
TLS: transport.TLSConfig{
526555
CertFile: opts.certFile,
@@ -532,12 +561,9 @@ func httpCall(ctx context.Context, request, response runtime.Object, opts *httpC
532561
if err != nil {
533562
return errors.Wrap(err, "http call failed: failed to create tls config")
534563
}
535-
// This also adds http2
536-
client.Transport = utilnet.SetTransportDefaults(&http.Transport{
537-
TLSClientConfig: tlsConfig,
538-
})
564+
httpRequest = httpRequest.WithContext(context.WithValue(httpRequest.Context(), tlsConfigContextKey, tlsConfig))
539565

540-
resp, err := client.Do(httpRequest)
566+
resp, err := httpClient.Do(httpRequest)
541567

542568
// Create http request metric.
543569
defer func() {

0 commit comments

Comments
 (0)