Track opened connections with a single tracker per authenticator

Kubernetes-commit: ecbff22ca134bd802127aab2be165d2770a9262a
This commit is contained in:
Jordan Liggitt
2021-01-08 12:13:19 -05:00
committed by Kubernetes Publisher
parent 9761a13537
commit 0c5bab64fe
2 changed files with 77 additions and 49 deletions

View File

@@ -18,7 +18,6 @@ package exec
import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"errors"
@@ -52,7 +51,6 @@ import (
)
const execInfoEnv = "KUBERNETES_EXEC_INFO"
const onRotateListWarningLength = 1000
const installHintVerboseHelp = `
It looks like you are trying to use a client-go credential plugin that is not installed.
@@ -177,6 +175,12 @@ func newAuthenticator(c *cache, config *api.ExecConfig, cluster *clientauthentic
return nil, fmt.Errorf("exec plugin: invalid apiVersion %q", config.APIVersion)
}
connTracker := connrotation.NewConnectionTracker()
defaultDialer := connrotation.NewDialerWithTracker(
(&net.Dialer{Timeout: 30 * time.Second, KeepAlive: 30 * time.Second}).DialContext,
connTracker,
)
a := &Authenticator{
cmd: config.Command,
args: config.Args,
@@ -196,6 +200,9 @@ func newAuthenticator(c *cache, config *api.ExecConfig, cluster *clientauthentic
interactive: terminal.IsTerminal(int(os.Stdout.Fd())),
now: time.Now,
environ: os.Environ,
defaultDialer: defaultDialer,
connTracker: connTracker,
}
for _, env := range config.Env {
@@ -229,6 +236,11 @@ type Authenticator struct {
now func() time.Time
environ func() []string
// defaultDialer is used for clients which don't specify a custom dialer
defaultDialer *connrotation.Dialer
// connTracker tracks all connections opened that we need to close when rotating a client certificate
connTracker *connrotation.ConnectionTracker
// Cached results.
//
// The mutex also guards calling the plugin. Since the plugin could be
@@ -236,8 +248,6 @@ type Authenticator struct {
mu sync.Mutex
cachedCreds *credentials
exp time.Time
onRotateList []func()
}
type credentials struct {
@@ -266,20 +276,12 @@ func (a *Authenticator) UpdateTransportConfig(c *transport.Config) error {
}
c.TLS.GetCert = a.cert
var dial func(ctx context.Context, network, addr string) (net.Conn, error)
var d *connrotation.Dialer
if c.Dial != nil {
dial = c.Dial
// if c has a custom dialer, we have to wrap it
d = connrotation.NewDialerWithTracker(c.Dial, a.connTracker)
} else {
dial = (&net.Dialer{Timeout: 30 * time.Second, KeepAlive: 30 * time.Second}).DialContext
}
d := connrotation.NewDialer(dial)
a.mu.Lock()
defer a.mu.Unlock()
a.onRotateList = append(a.onRotateList, d.CloseAll)
onRotateListLength := len(a.onRotateList)
if onRotateListLength > onRotateListWarningLength {
klog.Warningf("constructing many client instances from the same exec auth config can cause performance problems during cert rotation and can exhaust available network connections; %d clients constructed calling %q", onRotateListLength, a.cmd)
d = a.defaultDialer
}
c.Dial = d.DialContext
@@ -458,9 +460,7 @@ func (a *Authenticator) refreshCredsLocked(r *clientauthentication.Response) err
if oldCreds.cert != nil && oldCreds.cert.Leaf != nil {
metrics.ClientCertRotationAge.Observe(time.Now().Sub(oldCreds.cert.Leaf.NotBefore))
}
for _, onRotate := range a.onRotateList {
onRotate()
}
a.connTracker.CloseAll()
}
expiry := time.Time{}