func (a *Authenticator) UpdateTransportConfig(c *transport.Config) error {
	c.Wrap(func(rt http.RoundTripper) http.RoundTripper {
		return &roundTripper{a, rt}
	})
	if c.TLS.GetCert != nil {
		return errors.New("can't add TLS certificate callback: transport.Config.TLS.GetCert already set")
	}
	c.TLS.GetCert = a.cert
	var dial func(ctx context.Context, network, addr string) (net.Conn, error)
	if c.Dial != nil {
		dial = c.Dial
	} 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)
	}
	c.Dial = d.DialContext
	return nil
}
UpdateTransportConfig updates the transport.Config to use credentials
returned by the plugin.
package exec
import (
	"bytes"
	"context"
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"os/exec"
	"reflect"
	"sync"
	"time"
	"github.com/davecgh/go-spew/spew"
	"golang.org/x/crypto/ssh/terminal"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/client-go/pkg/apis/clientauthentication"
	"k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1"
	"k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
	"k8s.io/client-go/tools/clientcmd/api"
	"k8s.io/client-go/transport"
	"k8s.io/client-go/util/connrotation"
	"k8s.io/klog"
)
const execInfoEnv = "KUBERNETES_EXEC_INFO"
const onRotateListWarningLength = 1000
var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme)
func init() {
	v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
	utilruntime.Must(v1alpha1.AddToScheme(scheme))
	utilruntime.Must(v1beta1.AddToScheme(scheme))
	utilruntime.Must(clientauthentication.AddToScheme(scheme))
}
var (
	globalCache = newCache()
	apiVersions = map[string]schema.GroupVersion{
		v1alpha1.SchemeGroupVersion.String(): v1alpha1.SchemeGroupVersion,
		v1beta1.SchemeGroupVersion.String():  v1beta1.SchemeGroupVersion,
	}
)
func newCache() *cache {
	return &cache{m: make(map[string]*Authenticator)}
}
var spewConfig = &spew.ConfigState{DisableMethods: true, Indent: " "}
func cacheKey(c *api.ExecConfig) string {
	return spewConfig.Sprint(c)
}
type cache struct {
	mu sync.Mutex
	m  map[string]*Authenticator
}
func (c *cache) get(s string) (*Authenticator, bool) {
	c.mu.Lock()
	defer c.mu.Unlock()
	a, ok := c.m[s]
	return a, ok
}
func (c *cache) put(s string, a *Authenticator) *Authenticator {
	c.mu.Lock()
	defer c.mu.Unlock()
	existing, ok := c.m[s]
	if ok {
		return existing
	}
	c.m[s] = a
	return a
}
func GetAuthenticator(config *api.ExecConfig) (*Authenticator, error) {
	return newAuthenticator(globalCache, config)
}
func newAuthenticator(c *cache, config *api.ExecConfig) (*Authenticator, error) {
	key := cacheKey(config)
	if a, ok := c.get(key); ok {
		return a, nil
	}
	gv, ok := apiVersions[config.APIVersion]
	if !ok {
		return nil, fmt.Errorf("exec plugin: invalid apiVersion %q", config.APIVersion)
	}
	a := &Authenticator{
		cmd:   config.Command,
		args:  config.Args,
		group: gv,
		stdin:       os.Stdin,
		stderr:      os.Stderr,
		interactive: terminal.IsTerminal(int(os.Stdout.Fd())),
		now:         time.Now,
		environ:     os.Environ,
	}
	for _, env := range config.Env {
		a.env = append(a.env, env.Name+"="+env.Value)
	}
	return c.put(key, a), nil
}
type Authenticator struct {
	cmd   string
	args  []string
	group schema.GroupVersion
	env   []string
	stdin       io.Reader
	stderr      io.Writer
	interactive bool
	now         func() time.Time
	environ     func() []string
	mu          sync.Mutex
	cachedCreds *credentials
	exp         time.Time
	onRotateList []func()
}
type credentials struct {
	token string
	cert  *tls.Certificate
}