init
This commit is contained in:
		
							
								
								
									
										7
									
								
								vendor/k8s.io/client-go/transport/OWNERS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/k8s.io/client-go/transport/OWNERS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| reviewers: | ||||
| - smarterclayton | ||||
| - wojtek-t | ||||
| - deads2k | ||||
| - liggitt | ||||
| - krousey | ||||
| - caesarxuchao | ||||
							
								
								
									
										117
									
								
								vendor/k8s.io/client-go/transport/cache.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								vendor/k8s.io/client-go/transport/cache.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| /* | ||||
| 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 ( | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	utilnet "k8s.io/apimachinery/pkg/util/net" | ||||
| ) | ||||
|  | ||||
| // TlsTransportCache caches TLS http.RoundTrippers different configurations. The | ||||
| // same RoundTripper will be returned for configs with identical TLS options If | ||||
| // the config has no custom TLS options, http.DefaultTransport is returned. | ||||
| type tlsTransportCache struct { | ||||
| 	mu         sync.Mutex | ||||
| 	transports map[tlsCacheKey]*http.Transport | ||||
| } | ||||
|  | ||||
| const idleConnsPerHost = 25 | ||||
|  | ||||
| var tlsCache = &tlsTransportCache{transports: make(map[tlsCacheKey]*http.Transport)} | ||||
|  | ||||
| type tlsCacheKey struct { | ||||
| 	insecure   bool | ||||
| 	caData     string | ||||
| 	certData   string | ||||
| 	keyData    string | ||||
| 	getCert    string | ||||
| 	serverName string | ||||
| 	dial       string | ||||
| } | ||||
|  | ||||
| func (t tlsCacheKey) String() string { | ||||
| 	keyText := "<none>" | ||||
| 	if len(t.keyData) > 0 { | ||||
| 		keyText = "<redacted>" | ||||
| 	} | ||||
| 	return fmt.Sprintf("insecure:%v, caData:%#v, certData:%#v, keyData:%s, getCert: %s, serverName:%s, dial:%s", t.insecure, t.caData, t.certData, keyText, t.getCert, t.serverName, t.dial) | ||||
| } | ||||
|  | ||||
| func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) { | ||||
| 	key, err := tlsConfigKey(config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// Ensure we only create a single transport for the given TLS options | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
|  | ||||
| 	// See if we already have a custom transport for this config | ||||
| 	if t, ok := c.transports[key]; ok { | ||||
| 		return t, nil | ||||
| 	} | ||||
|  | ||||
| 	// Get the TLS options for this client config | ||||
| 	tlsConfig, err := TLSConfigFor(config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	// The options didn't require a custom TLS config | ||||
| 	if tlsConfig == nil && config.Dial == nil { | ||||
| 		return http.DefaultTransport, nil | ||||
| 	} | ||||
|  | ||||
| 	dial := config.Dial | ||||
| 	if dial == nil { | ||||
| 		dial = (&net.Dialer{ | ||||
| 			Timeout:   30 * time.Second, | ||||
| 			KeepAlive: 30 * time.Second, | ||||
| 		}).DialContext | ||||
| 	} | ||||
| 	// Cache a single transport for these options | ||||
| 	c.transports[key] = utilnet.SetTransportDefaults(&http.Transport{ | ||||
| 		Proxy:               http.ProxyFromEnvironment, | ||||
| 		TLSHandshakeTimeout: 10 * time.Second, | ||||
| 		TLSClientConfig:     tlsConfig, | ||||
| 		MaxIdleConnsPerHost: idleConnsPerHost, | ||||
| 		DialContext:         dial, | ||||
| 	}) | ||||
| 	return c.transports[key], nil | ||||
| } | ||||
|  | ||||
| // tlsConfigKey returns a unique key for tls.Config objects returned from TLSConfigFor | ||||
| func tlsConfigKey(c *Config) (tlsCacheKey, error) { | ||||
| 	// Make sure ca/key/cert content is loaded | ||||
| 	if err := loadTLSFiles(c); err != nil { | ||||
| 		return tlsCacheKey{}, err | ||||
| 	} | ||||
| 	return tlsCacheKey{ | ||||
| 		insecure:   c.TLS.Insecure, | ||||
| 		caData:     string(c.TLS.CAData), | ||||
| 		certData:   string(c.TLS.CertData), | ||||
| 		keyData:    string(c.TLS.KeyData), | ||||
| 		getCert:    fmt.Sprintf("%p", c.TLS.GetCert), | ||||
| 		serverName: c.TLS.ServerName, | ||||
| 		dial:       fmt.Sprintf("%p", c.Dial), | ||||
| 	}, nil | ||||
| } | ||||
							
								
								
									
										110
									
								
								vendor/k8s.io/client-go/transport/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								vendor/k8s.io/client-go/transport/config.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| /* | ||||
| 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 | ||||
|  | ||||
| 	// Impersonate is the config that this Config will impersonate using | ||||
| 	Impersonate ImpersonationConfig | ||||
|  | ||||
| 	// 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. | ||||
| 	WrapTransport func(rt http.RoundTripper) http.RoundTripper | ||||
|  | ||||
| 	// 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 | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| } | ||||
|  | ||||
| // 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. | ||||
|  | ||||
| 	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. | ||||
|  | ||||
| 	GetCert func() (*tls.Certificate, error) // Callback that returns a TLS client certificate. CertData, CertFile, KeyData and KeyFile supercede this field. | ||||
| } | ||||
							
								
								
									
										531
									
								
								vendor/k8s.io/client-go/transport/round_trippers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										531
									
								
								vendor/k8s.io/client-go/transport/round_trippers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,531 @@ | ||||
| /* | ||||
| 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 ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"k8s.io/klog" | ||||
|  | ||||
| 	utilnet "k8s.io/apimachinery/pkg/util/net" | ||||
| ) | ||||
|  | ||||
| // HTTPWrappersForConfig wraps a round tripper with any relevant layered | ||||
| // behavior from the config. Exposed to allow more clients that need HTTP-like | ||||
| // behavior but then must hijack the underlying connection (like WebSocket or | ||||
| // HTTP2 clients). Pure HTTP clients should use the RoundTripper returned from | ||||
| // New. | ||||
| func HTTPWrappersForConfig(config *Config, rt http.RoundTripper) (http.RoundTripper, error) { | ||||
| 	if config.WrapTransport != nil { | ||||
| 		rt = config.WrapTransport(rt) | ||||
| 	} | ||||
|  | ||||
| 	rt = DebugWrappers(rt) | ||||
|  | ||||
| 	// Set authentication wrappers | ||||
| 	switch { | ||||
| 	case config.HasBasicAuth() && config.HasTokenAuth(): | ||||
| 		return nil, fmt.Errorf("username/password or bearer token may be set, but not both") | ||||
| 	case config.HasTokenAuth(): | ||||
| 		rt = NewBearerAuthRoundTripper(config.BearerToken, rt) | ||||
| 	case config.HasBasicAuth(): | ||||
| 		rt = NewBasicAuthRoundTripper(config.Username, config.Password, rt) | ||||
| 	} | ||||
| 	if len(config.UserAgent) > 0 { | ||||
| 		rt = NewUserAgentRoundTripper(config.UserAgent, rt) | ||||
| 	} | ||||
| 	if len(config.Impersonate.UserName) > 0 || | ||||
| 		len(config.Impersonate.Groups) > 0 || | ||||
| 		len(config.Impersonate.Extra) > 0 { | ||||
| 		rt = NewImpersonatingRoundTripper(config.Impersonate, rt) | ||||
| 	} | ||||
| 	return rt, nil | ||||
| } | ||||
|  | ||||
| // DebugWrappers wraps a round tripper and logs based on the current log level. | ||||
| func DebugWrappers(rt http.RoundTripper) http.RoundTripper { | ||||
| 	switch { | ||||
| 	case bool(klog.V(9)): | ||||
| 		rt = newDebuggingRoundTripper(rt, debugCurlCommand, debugURLTiming, debugResponseHeaders) | ||||
| 	case bool(klog.V(8)): | ||||
| 		rt = newDebuggingRoundTripper(rt, debugJustURL, debugRequestHeaders, debugResponseStatus, debugResponseHeaders) | ||||
| 	case bool(klog.V(7)): | ||||
| 		rt = newDebuggingRoundTripper(rt, debugJustURL, debugRequestHeaders, debugResponseStatus) | ||||
| 	case bool(klog.V(6)): | ||||
| 		rt = newDebuggingRoundTripper(rt, debugURLTiming) | ||||
| 	} | ||||
|  | ||||
| 	return rt | ||||
| } | ||||
|  | ||||
| type requestCanceler interface { | ||||
| 	CancelRequest(*http.Request) | ||||
| } | ||||
|  | ||||
| type authProxyRoundTripper struct { | ||||
| 	username string | ||||
| 	groups   []string | ||||
| 	extra    map[string][]string | ||||
|  | ||||
| 	rt http.RoundTripper | ||||
| } | ||||
|  | ||||
| // NewAuthProxyRoundTripper provides a roundtripper which will add auth proxy fields to requests for | ||||
| // authentication terminating proxy cases | ||||
| // assuming you pull the user from the context: | ||||
| // username is the user.Info.GetName() of the user | ||||
| // groups is the user.Info.GetGroups() of the user | ||||
| // extra is the user.Info.GetExtra() of the user | ||||
| // extra can contain any additional information that the authenticator | ||||
| // thought was interesting, for example authorization scopes. | ||||
| // In order to faithfully round-trip through an impersonation flow, these keys | ||||
| // MUST be lowercase. | ||||
| func NewAuthProxyRoundTripper(username string, groups []string, extra map[string][]string, rt http.RoundTripper) http.RoundTripper { | ||||
| 	return &authProxyRoundTripper{ | ||||
| 		username: username, | ||||
| 		groups:   groups, | ||||
| 		extra:    extra, | ||||
| 		rt:       rt, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (rt *authProxyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { | ||||
| 	req = utilnet.CloneRequest(req) | ||||
| 	SetAuthProxyHeaders(req, rt.username, rt.groups, rt.extra) | ||||
|  | ||||
| 	return rt.rt.RoundTrip(req) | ||||
| } | ||||
|  | ||||
| // SetAuthProxyHeaders stomps the auth proxy header fields.  It mutates its argument. | ||||
| func SetAuthProxyHeaders(req *http.Request, username string, groups []string, extra map[string][]string) { | ||||
| 	req.Header.Del("X-Remote-User") | ||||
| 	req.Header.Del("X-Remote-Group") | ||||
| 	for key := range req.Header { | ||||
| 		if strings.HasPrefix(strings.ToLower(key), strings.ToLower("X-Remote-Extra-")) { | ||||
| 			req.Header.Del(key) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	req.Header.Set("X-Remote-User", username) | ||||
| 	for _, group := range groups { | ||||
| 		req.Header.Add("X-Remote-Group", group) | ||||
| 	} | ||||
| 	for key, values := range extra { | ||||
| 		for _, value := range values { | ||||
| 			req.Header.Add("X-Remote-Extra-"+headerKeyEscape(key), value) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (rt *authProxyRoundTripper) CancelRequest(req *http.Request) { | ||||
| 	if canceler, ok := rt.rt.(requestCanceler); ok { | ||||
| 		canceler.CancelRequest(req) | ||||
| 	} else { | ||||
| 		klog.Errorf("CancelRequest not implemented by %T", rt.rt) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (rt *authProxyRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt } | ||||
|  | ||||
| type userAgentRoundTripper struct { | ||||
| 	agent string | ||||
| 	rt    http.RoundTripper | ||||
| } | ||||
|  | ||||
| func NewUserAgentRoundTripper(agent string, rt http.RoundTripper) http.RoundTripper { | ||||
| 	return &userAgentRoundTripper{agent, rt} | ||||
| } | ||||
|  | ||||
| func (rt *userAgentRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { | ||||
| 	if len(req.Header.Get("User-Agent")) != 0 { | ||||
| 		return rt.rt.RoundTrip(req) | ||||
| 	} | ||||
| 	req = utilnet.CloneRequest(req) | ||||
| 	req.Header.Set("User-Agent", rt.agent) | ||||
| 	return rt.rt.RoundTrip(req) | ||||
| } | ||||
|  | ||||
| func (rt *userAgentRoundTripper) CancelRequest(req *http.Request) { | ||||
| 	if canceler, ok := rt.rt.(requestCanceler); ok { | ||||
| 		canceler.CancelRequest(req) | ||||
| 	} else { | ||||
| 		klog.Errorf("CancelRequest not implemented by %T", rt.rt) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (rt *userAgentRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt } | ||||
|  | ||||
| type basicAuthRoundTripper struct { | ||||
| 	username string | ||||
| 	password string | ||||
| 	rt       http.RoundTripper | ||||
| } | ||||
|  | ||||
| // NewBasicAuthRoundTripper will apply a BASIC auth authorization header to a | ||||
| // request unless it has already been set. | ||||
| func NewBasicAuthRoundTripper(username, password string, rt http.RoundTripper) http.RoundTripper { | ||||
| 	return &basicAuthRoundTripper{username, password, rt} | ||||
| } | ||||
|  | ||||
| func (rt *basicAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { | ||||
| 	if len(req.Header.Get("Authorization")) != 0 { | ||||
| 		return rt.rt.RoundTrip(req) | ||||
| 	} | ||||
| 	req = utilnet.CloneRequest(req) | ||||
| 	req.SetBasicAuth(rt.username, rt.password) | ||||
| 	return rt.rt.RoundTrip(req) | ||||
| } | ||||
|  | ||||
| func (rt *basicAuthRoundTripper) CancelRequest(req *http.Request) { | ||||
| 	if canceler, ok := rt.rt.(requestCanceler); ok { | ||||
| 		canceler.CancelRequest(req) | ||||
| 	} else { | ||||
| 		klog.Errorf("CancelRequest not implemented by %T", rt.rt) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (rt *basicAuthRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt } | ||||
|  | ||||
| // These correspond to the headers used in pkg/apis/authentication.  We don't want the package dependency, | ||||
| // but you must not change the values. | ||||
| const ( | ||||
| 	// ImpersonateUserHeader is used to impersonate a particular user during an API server request | ||||
| 	ImpersonateUserHeader = "Impersonate-User" | ||||
|  | ||||
| 	// ImpersonateGroupHeader is used to impersonate a particular group during an API server request. | ||||
| 	// It can be repeated multiplied times for multiple groups. | ||||
| 	ImpersonateGroupHeader = "Impersonate-Group" | ||||
|  | ||||
| 	// ImpersonateUserExtraHeaderPrefix is a prefix for a header used to impersonate an entry in the | ||||
| 	// extra map[string][]string for user.Info.  The key for the `extra` map is suffix. | ||||
| 	// The same key can be repeated multiple times to have multiple elements in the slice under a single key. | ||||
| 	// For instance: | ||||
| 	// Impersonate-Extra-Foo: one | ||||
| 	// Impersonate-Extra-Foo: two | ||||
| 	// results in extra["Foo"] = []string{"one", "two"} | ||||
| 	ImpersonateUserExtraHeaderPrefix = "Impersonate-Extra-" | ||||
| ) | ||||
|  | ||||
| type impersonatingRoundTripper struct { | ||||
| 	impersonate ImpersonationConfig | ||||
| 	delegate    http.RoundTripper | ||||
| } | ||||
|  | ||||
| // NewImpersonatingRoundTripper will add an Act-As header to a request unless it has already been set. | ||||
| func NewImpersonatingRoundTripper(impersonate ImpersonationConfig, delegate http.RoundTripper) http.RoundTripper { | ||||
| 	return &impersonatingRoundTripper{impersonate, delegate} | ||||
| } | ||||
|  | ||||
| func (rt *impersonatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { | ||||
| 	// use the user header as marker for the rest. | ||||
| 	if len(req.Header.Get(ImpersonateUserHeader)) != 0 { | ||||
| 		return rt.delegate.RoundTrip(req) | ||||
| 	} | ||||
| 	req = utilnet.CloneRequest(req) | ||||
| 	req.Header.Set(ImpersonateUserHeader, rt.impersonate.UserName) | ||||
|  | ||||
| 	for _, group := range rt.impersonate.Groups { | ||||
| 		req.Header.Add(ImpersonateGroupHeader, group) | ||||
| 	} | ||||
| 	for k, vv := range rt.impersonate.Extra { | ||||
| 		for _, v := range vv { | ||||
| 			req.Header.Add(ImpersonateUserExtraHeaderPrefix+headerKeyEscape(k), v) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return rt.delegate.RoundTrip(req) | ||||
| } | ||||
|  | ||||
| func (rt *impersonatingRoundTripper) CancelRequest(req *http.Request) { | ||||
| 	if canceler, ok := rt.delegate.(requestCanceler); ok { | ||||
| 		canceler.CancelRequest(req) | ||||
| 	} else { | ||||
| 		klog.Errorf("CancelRequest not implemented by %T", rt.delegate) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (rt *impersonatingRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.delegate } | ||||
|  | ||||
| type bearerAuthRoundTripper struct { | ||||
| 	bearer string | ||||
| 	rt     http.RoundTripper | ||||
| } | ||||
|  | ||||
| // NewBearerAuthRoundTripper adds the provided bearer token to a request | ||||
| // unless the authorization header has already been set. | ||||
| func NewBearerAuthRoundTripper(bearer string, rt http.RoundTripper) http.RoundTripper { | ||||
| 	return &bearerAuthRoundTripper{bearer, rt} | ||||
| } | ||||
|  | ||||
| func (rt *bearerAuthRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { | ||||
| 	if len(req.Header.Get("Authorization")) != 0 { | ||||
| 		return rt.rt.RoundTrip(req) | ||||
| 	} | ||||
|  | ||||
| 	req = utilnet.CloneRequest(req) | ||||
| 	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", rt.bearer)) | ||||
| 	return rt.rt.RoundTrip(req) | ||||
| } | ||||
|  | ||||
| func (rt *bearerAuthRoundTripper) CancelRequest(req *http.Request) { | ||||
| 	if canceler, ok := rt.rt.(requestCanceler); ok { | ||||
| 		canceler.CancelRequest(req) | ||||
| 	} else { | ||||
| 		klog.Errorf("CancelRequest not implemented by %T", rt.rt) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (rt *bearerAuthRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt } | ||||
|  | ||||
| // requestInfo keeps track of information about a request/response combination | ||||
| type requestInfo struct { | ||||
| 	RequestHeaders http.Header | ||||
| 	RequestVerb    string | ||||
| 	RequestURL     string | ||||
|  | ||||
| 	ResponseStatus  string | ||||
| 	ResponseHeaders http.Header | ||||
| 	ResponseErr     error | ||||
|  | ||||
| 	Duration time.Duration | ||||
| } | ||||
|  | ||||
| // newRequestInfo creates a new RequestInfo based on an http request | ||||
| func newRequestInfo(req *http.Request) *requestInfo { | ||||
| 	return &requestInfo{ | ||||
| 		RequestURL:     req.URL.String(), | ||||
| 		RequestVerb:    req.Method, | ||||
| 		RequestHeaders: req.Header, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // complete adds information about the response to the requestInfo | ||||
| func (r *requestInfo) complete(response *http.Response, err error) { | ||||
| 	if err != nil { | ||||
| 		r.ResponseErr = err | ||||
| 		return | ||||
| 	} | ||||
| 	r.ResponseStatus = response.Status | ||||
| 	r.ResponseHeaders = response.Header | ||||
| } | ||||
|  | ||||
| // toCurl returns a string that can be run as a command in a terminal (minus the body) | ||||
| func (r *requestInfo) toCurl() string { | ||||
| 	headers := "" | ||||
| 	for key, values := range r.RequestHeaders { | ||||
| 		for _, value := range values { | ||||
| 			headers += fmt.Sprintf(` -H %q`, fmt.Sprintf("%s: %s", key, value)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return fmt.Sprintf("curl -k -v -X%s %s '%s'", r.RequestVerb, headers, r.RequestURL) | ||||
| } | ||||
|  | ||||
| // debuggingRoundTripper will display information about the requests passing | ||||
| // through it based on what is configured | ||||
| type debuggingRoundTripper struct { | ||||
| 	delegatedRoundTripper http.RoundTripper | ||||
|  | ||||
| 	levels map[debugLevel]bool | ||||
| } | ||||
|  | ||||
| type debugLevel int | ||||
|  | ||||
| const ( | ||||
| 	debugJustURL debugLevel = iota | ||||
| 	debugURLTiming | ||||
| 	debugCurlCommand | ||||
| 	debugRequestHeaders | ||||
| 	debugResponseStatus | ||||
| 	debugResponseHeaders | ||||
| ) | ||||
|  | ||||
| func newDebuggingRoundTripper(rt http.RoundTripper, levels ...debugLevel) *debuggingRoundTripper { | ||||
| 	drt := &debuggingRoundTripper{ | ||||
| 		delegatedRoundTripper: rt, | ||||
| 		levels:                make(map[debugLevel]bool, len(levels)), | ||||
| 	} | ||||
| 	for _, v := range levels { | ||||
| 		drt.levels[v] = true | ||||
| 	} | ||||
| 	return drt | ||||
| } | ||||
|  | ||||
| func (rt *debuggingRoundTripper) CancelRequest(req *http.Request) { | ||||
| 	if canceler, ok := rt.delegatedRoundTripper.(requestCanceler); ok { | ||||
| 		canceler.CancelRequest(req) | ||||
| 	} else { | ||||
| 		klog.Errorf("CancelRequest not implemented by %T", rt.delegatedRoundTripper) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (rt *debuggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { | ||||
| 	reqInfo := newRequestInfo(req) | ||||
|  | ||||
| 	if rt.levels[debugJustURL] { | ||||
| 		klog.Infof("%s %s", reqInfo.RequestVerb, reqInfo.RequestURL) | ||||
| 	} | ||||
| 	if rt.levels[debugCurlCommand] { | ||||
| 		klog.Infof("%s", reqInfo.toCurl()) | ||||
|  | ||||
| 	} | ||||
| 	if rt.levels[debugRequestHeaders] { | ||||
| 		klog.Infof("Request Headers:") | ||||
| 		for key, values := range reqInfo.RequestHeaders { | ||||
| 			for _, value := range values { | ||||
| 				klog.Infof("    %s: %s", key, value) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	startTime := time.Now() | ||||
| 	response, err := rt.delegatedRoundTripper.RoundTrip(req) | ||||
| 	reqInfo.Duration = time.Since(startTime) | ||||
|  | ||||
| 	reqInfo.complete(response, err) | ||||
|  | ||||
| 	if rt.levels[debugURLTiming] { | ||||
| 		klog.Infof("%s %s %s in %d milliseconds", reqInfo.RequestVerb, reqInfo.RequestURL, reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond)) | ||||
| 	} | ||||
| 	if rt.levels[debugResponseStatus] { | ||||
| 		klog.Infof("Response Status: %s in %d milliseconds", reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond)) | ||||
| 	} | ||||
| 	if rt.levels[debugResponseHeaders] { | ||||
| 		klog.Infof("Response Headers:") | ||||
| 		for key, values := range reqInfo.ResponseHeaders { | ||||
| 			for _, value := range values { | ||||
| 				klog.Infof("    %s: %s", key, value) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return response, err | ||||
| } | ||||
|  | ||||
| func (rt *debuggingRoundTripper) WrappedRoundTripper() http.RoundTripper { | ||||
| 	return rt.delegatedRoundTripper | ||||
| } | ||||
|  | ||||
| func legalHeaderByte(b byte) bool { | ||||
| 	return int(b) < len(legalHeaderKeyBytes) && legalHeaderKeyBytes[b] | ||||
| } | ||||
|  | ||||
| func shouldEscape(b byte) bool { | ||||
| 	// url.PathUnescape() returns an error if any '%' is not followed by two | ||||
| 	// hexadecimal digits, so we'll intentionally encode it. | ||||
| 	return !legalHeaderByte(b) || b == '%' | ||||
| } | ||||
|  | ||||
| func headerKeyEscape(key string) string { | ||||
| 	buf := strings.Builder{} | ||||
| 	for i := 0; i < len(key); i++ { | ||||
| 		b := key[i] | ||||
| 		if shouldEscape(b) { | ||||
| 			// %-encode bytes that should be escaped: | ||||
| 			// https://tools.ietf.org/html/rfc3986#section-2.1 | ||||
| 			fmt.Fprintf(&buf, "%%%02X", b) | ||||
| 			continue | ||||
| 		} | ||||
| 		buf.WriteByte(b) | ||||
| 	} | ||||
| 	return buf.String() | ||||
| } | ||||
|  | ||||
| // legalHeaderKeyBytes was copied from net/http/lex.go's isTokenTable. | ||||
| // See https://httpwg.github.io/specs/rfc7230.html#rule.token.separators | ||||
| var legalHeaderKeyBytes = [127]bool{ | ||||
| 	'%':  true, | ||||
| 	'!':  true, | ||||
| 	'#':  true, | ||||
| 	'$':  true, | ||||
| 	'&':  true, | ||||
| 	'\'': true, | ||||
| 	'*':  true, | ||||
| 	'+':  true, | ||||
| 	'-':  true, | ||||
| 	'.':  true, | ||||
| 	'0':  true, | ||||
| 	'1':  true, | ||||
| 	'2':  true, | ||||
| 	'3':  true, | ||||
| 	'4':  true, | ||||
| 	'5':  true, | ||||
| 	'6':  true, | ||||
| 	'7':  true, | ||||
| 	'8':  true, | ||||
| 	'9':  true, | ||||
| 	'A':  true, | ||||
| 	'B':  true, | ||||
| 	'C':  true, | ||||
| 	'D':  true, | ||||
| 	'E':  true, | ||||
| 	'F':  true, | ||||
| 	'G':  true, | ||||
| 	'H':  true, | ||||
| 	'I':  true, | ||||
| 	'J':  true, | ||||
| 	'K':  true, | ||||
| 	'L':  true, | ||||
| 	'M':  true, | ||||
| 	'N':  true, | ||||
| 	'O':  true, | ||||
| 	'P':  true, | ||||
| 	'Q':  true, | ||||
| 	'R':  true, | ||||
| 	'S':  true, | ||||
| 	'T':  true, | ||||
| 	'U':  true, | ||||
| 	'W':  true, | ||||
| 	'V':  true, | ||||
| 	'X':  true, | ||||
| 	'Y':  true, | ||||
| 	'Z':  true, | ||||
| 	'^':  true, | ||||
| 	'_':  true, | ||||
| 	'`':  true, | ||||
| 	'a':  true, | ||||
| 	'b':  true, | ||||
| 	'c':  true, | ||||
| 	'd':  true, | ||||
| 	'e':  true, | ||||
| 	'f':  true, | ||||
| 	'g':  true, | ||||
| 	'h':  true, | ||||
| 	'i':  true, | ||||
| 	'j':  true, | ||||
| 	'k':  true, | ||||
| 	'l':  true, | ||||
| 	'm':  true, | ||||
| 	'n':  true, | ||||
| 	'o':  true, | ||||
| 	'p':  true, | ||||
| 	'q':  true, | ||||
| 	'r':  true, | ||||
| 	's':  true, | ||||
| 	't':  true, | ||||
| 	'u':  true, | ||||
| 	'v':  true, | ||||
| 	'w':  true, | ||||
| 	'x':  true, | ||||
| 	'y':  true, | ||||
| 	'z':  true, | ||||
| 	'|':  true, | ||||
| 	'~':  true, | ||||
| } | ||||
							
								
								
									
										169
									
								
								vendor/k8s.io/client-go/transport/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								vendor/k8s.io/client-go/transport/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | ||||
| /* | ||||
| 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 ( | ||||
| 	"crypto/tls" | ||||
| 	"crypto/x509" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| // New returns an http.RoundTripper that will provide the authentication | ||||
| // or transport level security defined by the provided Config. | ||||
| func New(config *Config) (http.RoundTripper, error) { | ||||
| 	// Set transport level security | ||||
| 	if config.Transport != nil && (config.HasCA() || config.HasCertAuth() || config.HasCertCallback() || config.TLS.Insecure) { | ||||
| 		return nil, fmt.Errorf("using a custom transport with TLS certificate options or the insecure flag is not allowed") | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		rt  http.RoundTripper | ||||
| 		err error | ||||
| 	) | ||||
|  | ||||
| 	if config.Transport != nil { | ||||
| 		rt = config.Transport | ||||
| 	} else { | ||||
| 		rt, err = tlsCache.get(config) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return HTTPWrappersForConfig(config, rt) | ||||
| } | ||||
|  | ||||
| // TLSConfigFor returns a tls.Config that will provide the transport level security defined | ||||
| // by the provided Config. Will return nil if no transport level security is requested. | ||||
| func TLSConfigFor(c *Config) (*tls.Config, error) { | ||||
| 	if !(c.HasCA() || c.HasCertAuth() || c.HasCertCallback() || c.TLS.Insecure || len(c.TLS.ServerName) > 0) { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 	if c.HasCA() && c.TLS.Insecure { | ||||
| 		return nil, fmt.Errorf("specifying a root certificates file with the insecure flag is not allowed") | ||||
| 	} | ||||
| 	if err := loadTLSFiles(c); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tls.Config{ | ||||
| 		// Can't use SSLv3 because of POODLE and BEAST | ||||
| 		// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher | ||||
| 		// Can't use TLSv1.1 because of RC4 cipher usage | ||||
| 		MinVersion:         tls.VersionTLS12, | ||||
| 		InsecureSkipVerify: c.TLS.Insecure, | ||||
| 		ServerName:         c.TLS.ServerName, | ||||
| 	} | ||||
|  | ||||
| 	if c.HasCA() { | ||||
| 		tlsConfig.RootCAs = rootCertPool(c.TLS.CAData) | ||||
| 	} | ||||
|  | ||||
| 	var staticCert *tls.Certificate | ||||
| 	if c.HasCertAuth() { | ||||
| 		// If key/cert were provided, verify them before setting up | ||||
| 		// tlsConfig.GetClientCertificate. | ||||
| 		cert, err := tls.X509KeyPair(c.TLS.CertData, c.TLS.KeyData) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		staticCert = &cert | ||||
| 	} | ||||
|  | ||||
| 	if c.HasCertAuth() || c.HasCertCallback() { | ||||
| 		tlsConfig.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) { | ||||
| 			// Note: static key/cert data always take precedence over cert | ||||
| 			// callback. | ||||
| 			if staticCert != nil { | ||||
| 				return staticCert, nil | ||||
| 			} | ||||
| 			if c.HasCertCallback() { | ||||
| 				cert, err := c.TLS.GetCert() | ||||
| 				if err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 				// GetCert may return empty value, meaning no cert. | ||||
| 				if cert != nil { | ||||
| 					return cert, nil | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			// Both c.TLS.CertData/KeyData were unset and GetCert didn't return | ||||
| 			// anything. Return an empty tls.Certificate, no client cert will | ||||
| 			// be sent to the server. | ||||
| 			return &tls.Certificate{}, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return tlsConfig, nil | ||||
| } | ||||
|  | ||||
| // loadTLSFiles copies the data from the CertFile, KeyFile, and CAFile fields into the CertData, | ||||
| // KeyData, and CAFile fields, or returns an error. If no error is returned, all three fields are | ||||
| // either populated or were empty to start. | ||||
| func loadTLSFiles(c *Config) error { | ||||
| 	var err error | ||||
| 	c.TLS.CAData, err = dataFromSliceOrFile(c.TLS.CAData, c.TLS.CAFile) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	c.TLS.CertData, err = dataFromSliceOrFile(c.TLS.CertData, c.TLS.CertFile) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	c.TLS.KeyData, err = dataFromSliceOrFile(c.TLS.KeyData, c.TLS.KeyFile) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // dataFromSliceOrFile returns data from the slice (if non-empty), or from the file, | ||||
| // or an error if an error occurred reading the file | ||||
| func dataFromSliceOrFile(data []byte, file string) ([]byte, error) { | ||||
| 	if len(data) > 0 { | ||||
| 		return data, nil | ||||
| 	} | ||||
| 	if len(file) > 0 { | ||||
| 		fileData, err := ioutil.ReadFile(file) | ||||
| 		if err != nil { | ||||
| 			return []byte{}, err | ||||
| 		} | ||||
| 		return fileData, nil | ||||
| 	} | ||||
| 	return nil, nil | ||||
| } | ||||
|  | ||||
| // rootCertPool returns nil if caData is empty.  When passed along, this will mean "use system CAs". | ||||
| // When caData is not empty, it will be the ONLY information used in the CertPool. | ||||
| func rootCertPool(caData []byte) *x509.CertPool { | ||||
| 	// What we really want is a copy of x509.systemRootsPool, but that isn't exposed.  It's difficult to build (see the go | ||||
| 	// code for a look at the platform specific insanity), so we'll use the fact that RootCAs == nil gives us the system values | ||||
| 	// It doesn't allow trusting either/or, but hopefully that won't be an issue | ||||
| 	if len(caData) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// if we have caData, use it | ||||
| 	certPool := x509.NewCertPool() | ||||
| 	certPool.AppendCertsFromPEM(caData) | ||||
| 	return certPool | ||||
| } | ||||
		Reference in New Issue
	
	Block a user