Upgrade k8s.io/client-go to version 2
This commit is contained in:
parent
a3b95f798b
commit
6f4c5dd4ce
675 changed files with 109006 additions and 90744 deletions
88
vendor/k8s.io/client-go/transport/cache.go
generated
vendored
Normal file
88
vendor/k8s.io/client-go/transport/cache.go
generated
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
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/client-go/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[string]*http.Transport
|
||||
}
|
||||
|
||||
const idleConnsPerHost = 25
|
||||
|
||||
var tlsCache = &tlsTransportCache{transports: make(map[string]*http.Transport)}
|
||||
|
||||
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 {
|
||||
return http.DefaultTransport, nil
|
||||
}
|
||||
|
||||
// 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,
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
})
|
||||
return c.transports[key], nil
|
||||
}
|
||||
|
||||
// tlsConfigKey returns a unique key for tls.Config objects returned from TLSConfigFor
|
||||
func tlsConfigKey(c *Config) (string, error) {
|
||||
// Make sure ca/key/cert content is loaded
|
||||
if err := loadTLSFiles(c); err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Only include the things that actually affect the tls.Config
|
||||
return fmt.Sprintf("%v/%x/%x/%x", c.TLS.Insecure, c.TLS.CAData, c.TLS.CertData, c.TLS.KeyData), nil
|
||||
}
|
84
vendor/k8s.io/client-go/transport/config.go
generated
vendored
Normal file
84
vendor/k8s.io/client-go/transport/config.go
generated
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
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 "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 username that this Config will impersonate
|
||||
Impersonate string
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
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.
|
||||
}
|
337
vendor/k8s.io/client-go/transport/round_trippers.go
generated
vendored
Normal file
337
vendor/k8s.io/client-go/transport/round_trippers.go
generated
vendored
Normal file
|
@ -0,0 +1,337 @@
|
|||
/*
|
||||
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"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// 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) > 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(glog.V(9)):
|
||||
rt = newDebuggingRoundTripper(rt, debugCurlCommand, debugURLTiming, debugResponseHeaders)
|
||||
case bool(glog.V(8)):
|
||||
rt = newDebuggingRoundTripper(rt, debugJustURL, debugRequestHeaders, debugResponseStatus, debugResponseHeaders)
|
||||
case bool(glog.V(7)):
|
||||
rt = newDebuggingRoundTripper(rt, debugJustURL, debugRequestHeaders, debugResponseStatus)
|
||||
case bool(glog.V(6)):
|
||||
rt = newDebuggingRoundTripper(rt, debugURLTiming)
|
||||
}
|
||||
|
||||
return rt
|
||||
}
|
||||
|
||||
type requestCanceler interface {
|
||||
CancelRequest(*http.Request)
|
||||
}
|
||||
|
||||
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 = 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 {
|
||||
glog.Errorf("CancelRequest not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
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 = 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 {
|
||||
glog.Errorf("CancelRequest not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *basicAuthRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
|
||||
|
||||
type impersonatingRoundTripper struct {
|
||||
impersonate string
|
||||
delegate http.RoundTripper
|
||||
}
|
||||
|
||||
// NewImpersonatingRoundTripper will add an Act-As header to a request unless it has already been set.
|
||||
func NewImpersonatingRoundTripper(impersonate string, delegate http.RoundTripper) http.RoundTripper {
|
||||
return &impersonatingRoundTripper{impersonate, delegate}
|
||||
}
|
||||
|
||||
func (rt *impersonatingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if len(req.Header.Get("Impersonate-User")) != 0 {
|
||||
return rt.delegate.RoundTrip(req)
|
||||
}
|
||||
req = cloneRequest(req)
|
||||
req.Header.Set("Impersonate-User", rt.impersonate)
|
||||
return rt.delegate.RoundTrip(req)
|
||||
}
|
||||
|
||||
func (rt *impersonatingRoundTripper) CancelRequest(req *http.Request) {
|
||||
if canceler, ok := rt.delegate.(requestCanceler); ok {
|
||||
canceler.CancelRequest(req)
|
||||
} else {
|
||||
glog.Errorf("CancelRequest not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
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 = 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 {
|
||||
glog.Errorf("CancelRequest not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *bearerAuthRoundTripper) WrappedRoundTripper() http.RoundTripper { return rt.rt }
|
||||
|
||||
// cloneRequest returns a clone of the provided *http.Request.
|
||||
// The clone is a shallow copy of the struct and its Header map.
|
||||
func cloneRequest(r *http.Request) *http.Request {
|
||||
// shallow copy of the struct
|
||||
r2 := new(http.Request)
|
||||
*r2 = *r
|
||||
// deep copy of the Header
|
||||
r2.Header = make(http.Header)
|
||||
for k, s := range r.Header {
|
||||
r2.Header[k] = s
|
||||
}
|
||||
return r2
|
||||
}
|
||||
|
||||
// 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 {
|
||||
glog.Errorf("CancelRequest not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *debuggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
reqInfo := newRequestInfo(req)
|
||||
|
||||
if rt.levels[debugJustURL] {
|
||||
glog.Infof("%s %s", reqInfo.RequestVerb, reqInfo.RequestURL)
|
||||
}
|
||||
if rt.levels[debugCurlCommand] {
|
||||
glog.Infof("%s", reqInfo.toCurl())
|
||||
|
||||
}
|
||||
if rt.levels[debugRequestHeaders] {
|
||||
glog.Infof("Request Headers:")
|
||||
for key, values := range reqInfo.RequestHeaders {
|
||||
for _, value := range values {
|
||||
glog.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] {
|
||||
glog.Infof("%s %s %s in %d milliseconds", reqInfo.RequestVerb, reqInfo.RequestURL, reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond))
|
||||
}
|
||||
if rt.levels[debugResponseStatus] {
|
||||
glog.Infof("Response Status: %s in %d milliseconds", reqInfo.ResponseStatus, reqInfo.Duration.Nanoseconds()/int64(time.Millisecond))
|
||||
}
|
||||
if rt.levels[debugResponseHeaders] {
|
||||
glog.Infof("Response Headers:")
|
||||
for key, values := range reqInfo.ResponseHeaders {
|
||||
for _, value := range values {
|
||||
glog.Infof(" %s: %s", key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response, err
|
||||
}
|
||||
|
||||
func (rt *debuggingRoundTripper) WrappedRoundTripper() http.RoundTripper {
|
||||
return rt.delegatedRoundTripper
|
||||
}
|
140
vendor/k8s.io/client-go/transport/transport.go
generated
vendored
Normal file
140
vendor/k8s.io/client-go/transport/transport.go
generated
vendored
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
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.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.TLS.Insecure) {
|
||||
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,
|
||||
}
|
||||
|
||||
if c.HasCA() {
|
||||
tlsConfig.RootCAs = rootCertPool(c.TLS.CAData)
|
||||
}
|
||||
|
||||
if c.HasCertAuth() {
|
||||
cert, err := tls.X509KeyPair(c.TLS.CertData, c.TLS.KeyData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue