From 1adab8ec3fff12a55ef5902426564a3886982330 Mon Sep 17 00:00:00 2001 From: Russell Centanni Date: Tue, 7 May 2024 10:59:55 -0400 Subject: [PATCH] client-go/transport: fix memory leak when using rest.Config Dial function with client.New and kubernetes.NewForConfig --- rest/transport.go | 2 +- transport/cache.go | 4 ++++ transport/cache_test.go | 17 +++++++++-------- transport/config.go | 3 +++ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/rest/transport.go b/rest/transport.go index 53f986cbf3..a2dcce4043 100644 --- a/rest/transport.go +++ b/rest/transport.go @@ -112,7 +112,7 @@ func (c *Config) TransportConfig() (*transport.Config, error) { } if c.Dial != nil { - conf.DialHolder = &transport.DialHolder{Dial: c.Dial} + conf.DialHolder = &transport.DialHolder{Dial: c.Dial, DisableCache: true} } if c.ExecProvider != nil && c.AuthProvider != nil { diff --git a/transport/cache.go b/transport/cache.go index 7c7f1b330f..83e5257ca3 100644 --- a/transport/cache.go +++ b/transport/cache.go @@ -156,6 +156,10 @@ func tlsConfigKey(c *Config) (tlsCacheKey, bool, error) { return tlsCacheKey{}, false, nil } + if c.DialHolder != nil && c.DialHolder.DisableCache { + return tlsCacheKey{}, false, nil + } + k := tlsCacheKey{ insecure: c.TLS.Insecure, caData: string(c.TLS.CAData), diff --git a/transport/cache_test.go b/transport/cache_test.go index f2e455ccb0..94862fd15f 100644 --- a/transport/cache_test.go +++ b/transport/cache_test.go @@ -71,13 +71,14 @@ func TestTLSConfigKey(t *testing.T) { dialer := net.Dialer{} getCert := &GetCertHolder{GetCert: func() (*tls.Certificate, error) { return nil, nil }} uniqueConfigurations := map[string]*Config{ - "proxy": {Proxy: func(request *http.Request) (*url.URL, error) { return nil, nil }}, - "no tls": {}, - "dialer": {DialHolder: &DialHolder{Dial: dialer.DialContext}}, - "dialer2": {DialHolder: &DialHolder{Dial: func(ctx context.Context, network, address string) (net.Conn, error) { return nil, nil }}}, - "insecure": {TLS: TLSConfig{Insecure: true}}, - "cadata 1": {TLS: TLSConfig{CAData: []byte{1}}}, - "cadata 2": {TLS: TLSConfig{CAData: []byte{2}}}, + "proxy": {Proxy: func(request *http.Request) (*url.URL, error) { return nil, nil }}, + "no tls": {}, + "dialer": {DialHolder: &DialHolder{Dial: dialer.DialContext}}, + "dialer with cache disabled": {DialHolder: &DialHolder{DisableCache: true, Dial: dialer.DialContext}}, + "dialer2": {DialHolder: &DialHolder{Dial: func(ctx context.Context, network, address string) (net.Conn, error) { return nil, nil }}}, + "insecure": {TLS: TLSConfig{Insecure: true}}, + "cadata 1": {TLS: TLSConfig{CAData: []byte{1}}}, + "cadata 2": {TLS: TLSConfig{CAData: []byte{2}}}, "cert 1, key 1": { TLS: TLSConfig{ CertData: []byte{1}, @@ -157,7 +158,7 @@ func TestTLSConfigKey(t *testing.T) { continue } - shouldCacheA := valueA.Proxy == nil + shouldCacheA := valueA.Proxy == nil && (valueA.DialHolder == nil || !valueA.DialHolder.DisableCache) if shouldCacheA != canCacheA { t.Errorf("Unexpected canCache=false for " + nameA) } diff --git a/transport/config.go b/transport/config.go index d8a3d64b30..50a0e8db15 100644 --- a/transport/config.go +++ b/transport/config.go @@ -82,6 +82,9 @@ type Config struct { // DialHolder is used to make the wrapped function comparable so that it can be used as a map key. type DialHolder struct { Dial func(ctx context.Context, network, address string) (net.Conn, error) + + // DisableCache disables TLS config caching for this DialHolder. + DisableCache bool } // ImpersonationConfig has all the available impersonation options