From 3357b5ecf42db9bcf6e54c9d2b6712cfbae077bf Mon Sep 17 00:00:00 2001 From: Andrew Lytvynov Date: Wed, 25 Jul 2018 16:22:32 -0700 Subject: [PATCH] Set connrotation dialer via restclient.Config.Dialer Instead of Transport. This fixes ExecPlugin, which fails if restclient.Config.Transport is set. --- pkg/kubelet/certificate/transport.go | 114 ++++++++++-------- .../plugin/pkg/client/auth/exec/exec.go | 18 +-- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/pkg/kubelet/certificate/transport.go b/pkg/kubelet/certificate/transport.go index 76caa20a753..436bb8b4c96 100644 --- a/pkg/kubelet/certificate/transport.go +++ b/pkg/kubelet/certificate/transport.go @@ -65,74 +65,84 @@ func updateTransport(stopCh <-chan struct{}, period time.Duration, clientConfig d := connrotation.NewDialer((&net.Dialer{Timeout: 30 * time.Second, KeepAlive: 30 * time.Second}).DialContext) + if clientCertificateManager != nil { + if err := addCertRotation(stopCh, period, clientConfig, clientCertificateManager, exitAfter, d); err != nil { + return nil, err + } + } else { + clientConfig.Dial = d.DialContext + } + + return d.CloseAll, nil +} + +func addCertRotation(stopCh <-chan struct{}, period time.Duration, clientConfig *restclient.Config, clientCertificateManager certificate.Manager, exitAfter time.Duration, d *connrotation.Dialer) error { tlsConfig, err := restclient.TLSConfigFor(clientConfig) if err != nil { - return nil, fmt.Errorf("unable to configure TLS for the rest client: %v", err) + return fmt.Errorf("unable to configure TLS for the rest client: %v", err) } if tlsConfig == nil { tlsConfig = &tls.Config{} } - if clientCertificateManager != nil { - tlsConfig.Certificates = nil - tlsConfig.GetClientCertificate = func(requestInfo *tls.CertificateRequestInfo) (*tls.Certificate, error) { - cert := clientCertificateManager.Current() - if cert == nil { - return &tls.Certificate{Certificate: nil}, nil + tlsConfig.Certificates = nil + tlsConfig.GetClientCertificate = func(requestInfo *tls.CertificateRequestInfo) (*tls.Certificate, error) { + cert := clientCertificateManager.Current() + if cert == nil { + return &tls.Certificate{Certificate: nil}, nil + } + return cert, nil + } + + lastCertAvailable := time.Now() + lastCert := clientCertificateManager.Current() + go wait.Until(func() { + curr := clientCertificateManager.Current() + + if exitAfter > 0 { + now := time.Now() + if curr == nil { + // the certificate has been deleted from disk or is otherwise corrupt + if now.After(lastCertAvailable.Add(exitAfter)) { + if clientCertificateManager.ServerHealthy() { + glog.Fatalf("It has been %s since a valid client cert was found and the server is responsive, exiting.", exitAfter) + } else { + glog.Errorf("It has been %s since a valid client cert was found, but the server is not responsive. A restart may be necessary to retrieve new initial credentials.", exitAfter) + } + } + } else { + // the certificate is expired + if now.After(curr.Leaf.NotAfter) { + if clientCertificateManager.ServerHealthy() { + glog.Fatalf("The currently active client certificate has expired and the server is responsive, exiting.") + } else { + glog.Errorf("The currently active client certificate has expired, but the server is not responsive. A restart may be necessary to retrieve new initial credentials.") + } + } + lastCertAvailable = now } - return cert, nil } - lastCertAvailable := time.Now() - lastCert := clientCertificateManager.Current() - go wait.Until(func() { - curr := clientCertificateManager.Current() + if curr == nil || lastCert == curr { + // Cert hasn't been rotated. + return + } + lastCert = curr - if exitAfter > 0 { - now := time.Now() - if curr == nil { - // the certificate has been deleted from disk or is otherwise corrupt - if now.After(lastCertAvailable.Add(exitAfter)) { - if clientCertificateManager.ServerHealthy() { - glog.Fatalf("It has been %s since a valid client cert was found and the server is responsive, exiting.", exitAfter) - } else { - glog.Errorf("It has been %s since a valid client cert was found, but the server is not responsive. A restart may be necessary to retrieve new initial credentials.", exitAfter) - } - } - } else { - // the certificate is expired - if now.After(curr.Leaf.NotAfter) { - if clientCertificateManager.ServerHealthy() { - glog.Fatalf("The currently active client certificate has expired and the server is responsive, exiting.") - } else { - glog.Errorf("The currently active client certificate has expired, but the server is not responsive. A restart may be necessary to retrieve new initial credentials.") - } - } - lastCertAvailable = now - } - } - - if curr == nil || lastCert == curr { - // Cert hasn't been rotated. - return - } - lastCert = curr - - glog.Infof("certificate rotation detected, shutting down client connections to start using new credentials") - // The cert has been rotated. Close all existing connections to force the client - // to reperform its TLS handshake with new cert. - // - // See: https://github.com/kubernetes-incubator/bootkube/pull/663#issuecomment-318506493 - d.CloseAll() - }, period, stopCh) - } + glog.Infof("certificate rotation detected, shutting down client connections to start using new credentials") + // The cert has been rotated. Close all existing connections to force the client + // to reperform its TLS handshake with new cert. + // + // See: https://github.com/kubernetes-incubator/bootkube/pull/663#issuecomment-318506493 + d.CloseAll() + }, period, stopCh) clientConfig.Transport = utilnet.SetTransportDefaults(&http.Transport{ Proxy: http.ProxyFromEnvironment, TLSHandshakeTimeout: 10 * time.Second, TLSClientConfig: tlsConfig, MaxIdleConnsPerHost: 25, - DialContext: d.DialContext, // Use custom dialer. + DialContext: d.DialContext, }) // Zero out all existing TLS options since our new transport enforces them. @@ -144,5 +154,5 @@ func updateTransport(stopCh <-chan struct{}, period time.Duration, clientConfig clientConfig.CAFile = "" clientConfig.Insecure = false - return d.CloseAll, nil + return nil } diff --git a/staging/src/k8s.io/client-go/plugin/pkg/client/auth/exec/exec.go b/staging/src/k8s.io/client-go/plugin/pkg/client/auth/exec/exec.go index c7a86f186b3..cae9d0d618e 100644 --- a/staging/src/k8s.io/client-go/plugin/pkg/client/auth/exec/exec.go +++ b/staging/src/k8s.io/client-go/plugin/pkg/client/auth/exec/exec.go @@ -20,6 +20,7 @@ import ( "bytes" "context" "crypto/tls" + "errors" "fmt" "io" "net" @@ -179,21 +180,10 @@ func (a *Authenticator) UpdateTransportConfig(c *transport.Config) error { return &roundTripper{a, rt} } - getCert := c.TLS.GetCert - c.TLS.GetCert = func() (*tls.Certificate, error) { - // If previous GetCert is present and returns a valid non-nil - // certificate, use that. Otherwise use cert from exec plugin. - if getCert != nil { - cert, err := getCert() - if err != nil { - return nil, err - } - if cert != nil { - return cert, nil - } - } - return a.cert() + 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 {