mirror of
https://github.com/kubernetes/client-go.git
synced 2025-10-21 22:09:33 +00:00
Close outbound connections when using a cert callback and certificates rotate. This means that we won't get into a situation where we have open TLS connections using expires certs, which would get unauthorized errors at the apiserver Attempt to retrieve a new certificate if open connections near expiry, to prevent the case where the cert expires but we haven't yet opened a new TLS connection and so GetClientCertificate hasn't been called. Move certificate rotation logic to a separate function Rely on generic transport approach to handle closing TLS client connections in exec plugin; no need to use a custom dialer as this is now the default behaviour of the transport when faced with a cert callback. As a result of handling this case, it is now safe to apply the transport approach even in cases where there is a custom Dialer (this will not affect kubelet connrotation behaviour, because that uses a custom transport, not just a dialer). Check expiry of the full TLS certificate chain that will be presented, not only the leaf. Only do this check when the certificate actually rotates. Start the certificate as a zero value, not nil, so that we don't see a rotation when there is in fact no client certificate Drain the timer when we first initialize it, to prevent immediate rotation. Additionally, calling Stop() on the timer isn't necessary. Don't close connections on the first 'rotation' Remove RotateCertFromDisk and RotateClientCertFromDisk flags. Instead simply default to rotating certificates from disk whenever files are exclusively provided. Add integration test for client certificate rotation Simplify logic; rotate every 5 mins Instead of trying to be clever and checking for rotation just before an expiry, let's match the logic of the new apiserver cert rotation logic as much as possible. We write a controller that checks for rotation every 5 mins. We also check on every new connection. Respond to review Fix kubelet certificate rotation logic The kubelet rotation logic seems to be broken because it expects its cert files to end up as cert data whereas in fact they end up as a callback. We should just call the tlsConfig GetCertificate callback as this obtains a current cert even in cases where a static cert is provided, and check that for validity. Later on we can refactor all of the kubelet logic so that all it does is write files to disk, and the cert rotation work does the rest. Only read certificates once a second at most Respond to review 1) Don't blat the cert file names 2) Make it more obvious where we have a neverstop 3) Naming 4) Verbosity Avoid cache busting Use filenames as cache keys when rotation is enabled, and add the rotation later in the creation of the transport. Caller should start the rotating dialer Add continuous request rotation test Rebase: use context in List/Watch Swap goroutine around Retry GETs on net.IsProbableEOF Refactor certRotatingDialer For simplicity, don't affect cert callbacks To reduce change surface, lets not try to handle the case of a changing GetCert callback in this PR. Reverting this commit should be sufficient to handle that case in a later PR. This PR will focus only on rotating certificate and key files. Therefore, we don't need to modify the exec auth plugin. Fix copyright year Kubernetes-commit: 929b1559a0b855d996257ab3ad5364605edc253d
138 lines
5.1 KiB
Go
138 lines
5.1 KiB
Go
/*
|
|
Copyright 2015 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package transport
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"net"
|
|
"net/http"
|
|
)
|
|
|
|
// Config holds various options for establishing a transport.
|
|
type Config struct {
|
|
// UserAgent is an optional field that specifies the caller of this
|
|
// request.
|
|
UserAgent string
|
|
|
|
// The base TLS configuration for this transport.
|
|
TLS TLSConfig
|
|
|
|
// Username and password for basic authentication
|
|
Username string
|
|
Password string
|
|
|
|
// Bearer token for authentication
|
|
BearerToken string
|
|
|
|
// Path to a file containing a BearerToken.
|
|
// If set, the contents are periodically read.
|
|
// The last successfully read value takes precedence over BearerToken.
|
|
BearerTokenFile string
|
|
|
|
// Impersonate is the config that this Config will impersonate using
|
|
Impersonate ImpersonationConfig
|
|
|
|
// DisableCompression bypasses automatic GZip compression requests to the
|
|
// server.
|
|
DisableCompression bool
|
|
|
|
// Transport may be used for custom HTTP behavior. This attribute may
|
|
// not be specified with the TLS client certificate options. Use
|
|
// WrapTransport for most client level operations.
|
|
Transport http.RoundTripper
|
|
|
|
// WrapTransport will be invoked for custom HTTP behavior after the
|
|
// underlying transport is initialized (either the transport created
|
|
// from TLSClientConfig, Transport, or http.DefaultTransport). The
|
|
// config may layer other RoundTrippers on top of the returned
|
|
// RoundTripper.
|
|
//
|
|
// A future release will change this field to an array. Use config.Wrap()
|
|
// instead of setting this value directly.
|
|
WrapTransport WrapperFunc
|
|
|
|
// Dial specifies the dial function for creating unencrypted TCP connections.
|
|
Dial func(ctx context.Context, network, address string) (net.Conn, error)
|
|
}
|
|
|
|
// ImpersonationConfig has all the available impersonation options
|
|
type ImpersonationConfig struct {
|
|
// UserName matches user.Info.GetName()
|
|
UserName string
|
|
// Groups matches user.Info.GetGroups()
|
|
Groups []string
|
|
// Extra matches user.Info.GetExtra()
|
|
Extra map[string][]string
|
|
}
|
|
|
|
// HasCA returns whether the configuration has a certificate authority or not.
|
|
func (c *Config) HasCA() bool {
|
|
return len(c.TLS.CAData) > 0 || len(c.TLS.CAFile) > 0
|
|
}
|
|
|
|
// HasBasicAuth returns whether the configuration has basic authentication or not.
|
|
func (c *Config) HasBasicAuth() bool {
|
|
return len(c.Username) != 0
|
|
}
|
|
|
|
// HasTokenAuth returns whether the configuration has token authentication or not.
|
|
func (c *Config) HasTokenAuth() bool {
|
|
return len(c.BearerToken) != 0 || len(c.BearerTokenFile) != 0
|
|
}
|
|
|
|
// HasCertAuth returns whether the configuration has certificate authentication or not.
|
|
func (c *Config) HasCertAuth() bool {
|
|
return (len(c.TLS.CertData) != 0 || len(c.TLS.CertFile) != 0) && (len(c.TLS.KeyData) != 0 || len(c.TLS.KeyFile) != 0)
|
|
}
|
|
|
|
// HasCertCallbacks returns whether the configuration has certificate callback or not.
|
|
func (c *Config) HasCertCallback() bool {
|
|
return c.TLS.GetCert != nil
|
|
}
|
|
|
|
// Wrap adds a transport middleware function that will give the caller
|
|
// an opportunity to wrap the underlying http.RoundTripper prior to the
|
|
// first API call being made. The provided function is invoked after any
|
|
// existing transport wrappers are invoked.
|
|
func (c *Config) Wrap(fn WrapperFunc) {
|
|
c.WrapTransport = Wrappers(c.WrapTransport, fn)
|
|
}
|
|
|
|
// TLSConfig holds the information needed to set up a TLS transport.
|
|
type TLSConfig struct {
|
|
CAFile string // Path of the PEM-encoded server trusted root certificates.
|
|
CertFile string // Path of the PEM-encoded client certificate.
|
|
KeyFile string // Path of the PEM-encoded client key.
|
|
ReloadTLSFiles bool // Set to indicate that the original config provided files, and that they should be reloaded
|
|
|
|
Insecure bool // Server should be accessed without verifying the certificate. For testing only.
|
|
ServerName string // Override for the server name passed to the server for SNI and used to verify certificates.
|
|
|
|
CAData []byte // Bytes of the PEM-encoded server trusted root certificates. Supercedes CAFile.
|
|
CertData []byte // Bytes of the PEM-encoded client certificate. Supercedes CertFile.
|
|
KeyData []byte // Bytes of the PEM-encoded client key. Supercedes KeyFile.
|
|
|
|
// NextProtos is a list of supported application level protocols, in order of preference.
|
|
// Used to populate tls.Config.NextProtos.
|
|
// To indicate to the server http/1.1 is preferred over http/2, set to ["http/1.1", "h2"] (though the server is free to ignore that preference).
|
|
// To use only http/1.1, set to ["http/1.1"].
|
|
NextProtos []string
|
|
|
|
GetCert func() (*tls.Certificate, error) // Callback that returns a TLS client certificate. CertData, CertFile, KeyData and KeyFile supercede this field.
|
|
}
|