mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-11 13:02:14 +00:00
SPDY roundtripper must respect InsecureSkipVerify
This commit is contained in:
parent
3616b4bfec
commit
5cc943d3bf
@ -53,6 +53,10 @@ type SpdyRoundTripper struct {
|
|||||||
|
|
||||||
// Dialer is the dialer used to connect. Used if non-nil.
|
// Dialer is the dialer used to connect. Used if non-nil.
|
||||||
Dialer *net.Dialer
|
Dialer *net.Dialer
|
||||||
|
|
||||||
|
// proxier knows which proxy to use given a request, defaults to http.ProxyFromEnvironment
|
||||||
|
// Used primarily for mocking the proxy discovery in tests.
|
||||||
|
proxier func(req *http.Request) (*url.URL, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRoundTripper creates a new SpdyRoundTripper that will use
|
// NewRoundTripper creates a new SpdyRoundTripper that will use
|
||||||
@ -70,7 +74,11 @@ func NewSpdyRoundTripper(tlsConfig *tls.Config) *SpdyRoundTripper {
|
|||||||
// dial dials the host specified by req, using TLS if appropriate, optionally
|
// dial dials the host specified by req, using TLS if appropriate, optionally
|
||||||
// using a proxy server if one is configured via environment variables.
|
// using a proxy server if one is configured via environment variables.
|
||||||
func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) {
|
func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) {
|
||||||
proxyURL, err := http.ProxyFromEnvironment(req)
|
proxier := s.proxier
|
||||||
|
if proxier == nil {
|
||||||
|
proxier = http.ProxyFromEnvironment
|
||||||
|
}
|
||||||
|
proxyURL, err := proxier(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -106,7 +114,7 @@ func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) {
|
|||||||
return rwc, nil
|
return rwc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
host, _, err := net.SplitHostPort(req.URL.Host)
|
host, _, err := net.SplitHostPort(targetHost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -122,6 +130,11 @@ func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return if we were configured to skip validation
|
||||||
|
if s.tlsConfig != nil && s.tlsConfig.InsecureSkipVerify {
|
||||||
|
return tlsConn, nil
|
||||||
|
}
|
||||||
|
|
||||||
if err := tlsConn.VerifyHostname(host); err != nil {
|
if err := tlsConn.VerifyHostname(host); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -22,20 +22,48 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/elazarl/goproxy"
|
||||||
"k8s.io/kubernetes/pkg/util/httpstream"
|
"k8s.io/kubernetes/pkg/util/httpstream"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRoundTripAndNewConnection(t *testing.T) {
|
func TestRoundTripAndNewConnection(t *testing.T) {
|
||||||
|
|
||||||
localhostPool := x509.NewCertPool()
|
localhostPool := x509.NewCertPool()
|
||||||
if !localhostPool.AppendCertsFromPEM(localhostCert) {
|
if !localhostPool.AppendCertsFromPEM(localhostCert) {
|
||||||
t.Errorf("error setting up localhostCert pool")
|
t.Errorf("error setting up localhostCert pool")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
httpsServerInvalidHostname := func(h http.Handler) *httptest.Server {
|
||||||
|
cert, err := tls.X509KeyPair(exampleCert, exampleKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("https (invalid hostname): proxy_test: %v", err)
|
||||||
|
}
|
||||||
|
ts := httptest.NewUnstartedServer(h)
|
||||||
|
ts.TLS = &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
}
|
||||||
|
ts.StartTLS()
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
|
||||||
|
httpsServerValidHostname := func(h http.Handler) *httptest.Server {
|
||||||
|
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("https (valid hostname): proxy_test: %v", err)
|
||||||
|
}
|
||||||
|
ts := httptest.NewUnstartedServer(h)
|
||||||
|
ts.TLS = &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
}
|
||||||
|
ts.StartTLS()
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
serverFunc func(http.Handler) *httptest.Server
|
serverFunc func(http.Handler) *httptest.Server
|
||||||
|
proxyServerFunc func(http.Handler) *httptest.Server
|
||||||
clientTLS *tls.Config
|
clientTLS *tls.Config
|
||||||
serverConnectionHeader string
|
serverConnectionHeader string
|
||||||
serverUpgradeHeader string
|
serverUpgradeHeader string
|
||||||
@ -78,37 +106,85 @@ func TestRoundTripAndNewConnection(t *testing.T) {
|
|||||||
shouldError: false,
|
shouldError: false,
|
||||||
},
|
},
|
||||||
"https (invalid hostname + InsecureSkipVerify)": {
|
"https (invalid hostname + InsecureSkipVerify)": {
|
||||||
serverFunc: func(h http.Handler) *httptest.Server {
|
serverFunc: httpsServerInvalidHostname,
|
||||||
cert, err := tls.X509KeyPair(exampleCert, exampleKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("https (invalid hostname): proxy_test: %v", err)
|
|
||||||
}
|
|
||||||
ts := httptest.NewUnstartedServer(h)
|
|
||||||
ts.TLS = &tls.Config{
|
|
||||||
Certificates: []tls.Certificate{cert},
|
|
||||||
}
|
|
||||||
ts.StartTLS()
|
|
||||||
return ts
|
|
||||||
},
|
|
||||||
clientTLS: &tls.Config{InsecureSkipVerify: true},
|
clientTLS: &tls.Config{InsecureSkipVerify: true},
|
||||||
serverConnectionHeader: "Upgrade",
|
serverConnectionHeader: "Upgrade",
|
||||||
serverUpgradeHeader: "SPDY/3.1",
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
serverStatusCode: http.StatusSwitchingProtocols,
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
shouldError: false,
|
shouldError: false,
|
||||||
},
|
},
|
||||||
|
"https (invalid hostname + hostname verification)": {
|
||||||
|
serverFunc: httpsServerInvalidHostname,
|
||||||
|
clientTLS: &tls.Config{InsecureSkipVerify: false},
|
||||||
|
serverConnectionHeader: "Upgrade",
|
||||||
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
|
shouldError: true,
|
||||||
|
},
|
||||||
"https (valid hostname + RootCAs)": {
|
"https (valid hostname + RootCAs)": {
|
||||||
serverFunc: func(h http.Handler) *httptest.Server {
|
serverFunc: httpsServerValidHostname,
|
||||||
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
|
clientTLS: &tls.Config{RootCAs: localhostPool},
|
||||||
if err != nil {
|
serverConnectionHeader: "Upgrade",
|
||||||
t.Errorf("https (valid hostname): proxy_test: %v", err)
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
}
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
ts := httptest.NewUnstartedServer(h)
|
shouldError: false,
|
||||||
ts.TLS = &tls.Config{
|
},
|
||||||
Certificates: []tls.Certificate{cert},
|
"proxied http->http": {
|
||||||
}
|
serverFunc: httptest.NewServer,
|
||||||
ts.StartTLS()
|
proxyServerFunc: httptest.NewServer,
|
||||||
return ts
|
serverConnectionHeader: "Upgrade",
|
||||||
},
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
|
shouldError: false,
|
||||||
|
},
|
||||||
|
"proxied https (invalid hostname + InsecureSkipVerify) -> http": {
|
||||||
|
serverFunc: httptest.NewServer,
|
||||||
|
proxyServerFunc: httpsServerInvalidHostname,
|
||||||
|
clientTLS: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
serverConnectionHeader: "Upgrade",
|
||||||
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
|
shouldError: false,
|
||||||
|
},
|
||||||
|
"proxied https (invalid hostname + hostname verification) -> http": {
|
||||||
|
serverFunc: httptest.NewServer,
|
||||||
|
proxyServerFunc: httpsServerInvalidHostname,
|
||||||
|
clientTLS: &tls.Config{InsecureSkipVerify: false},
|
||||||
|
serverConnectionHeader: "Upgrade",
|
||||||
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
|
shouldError: true, // fails because the client doesn't trust the proxy
|
||||||
|
},
|
||||||
|
"proxied https (valid hostname + RootCAs) -> http": {
|
||||||
|
serverFunc: httptest.NewServer,
|
||||||
|
proxyServerFunc: httpsServerValidHostname,
|
||||||
|
clientTLS: &tls.Config{RootCAs: localhostPool},
|
||||||
|
serverConnectionHeader: "Upgrade",
|
||||||
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
|
shouldError: false,
|
||||||
|
},
|
||||||
|
"proxied https (invalid hostname + InsecureSkipVerify) -> https (invalid hostname)": {
|
||||||
|
serverFunc: httpsServerInvalidHostname,
|
||||||
|
proxyServerFunc: httpsServerInvalidHostname,
|
||||||
|
clientTLS: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
serverConnectionHeader: "Upgrade",
|
||||||
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
|
shouldError: false, // works because the test proxy ignores TLS errors
|
||||||
|
},
|
||||||
|
"proxied https (invalid hostname + hostname verification) -> https (invalid hostname)": {
|
||||||
|
serverFunc: httpsServerInvalidHostname,
|
||||||
|
proxyServerFunc: httpsServerInvalidHostname,
|
||||||
|
clientTLS: &tls.Config{InsecureSkipVerify: false},
|
||||||
|
serverConnectionHeader: "Upgrade",
|
||||||
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
|
serverStatusCode: http.StatusSwitchingProtocols,
|
||||||
|
shouldError: true, // fails because the client doesn't trust the proxy
|
||||||
|
},
|
||||||
|
"proxied https (valid hostname + RootCAs) -> https (valid hostname + RootCAs)": {
|
||||||
|
serverFunc: httpsServerValidHostname,
|
||||||
|
proxyServerFunc: httpsServerValidHostname,
|
||||||
clientTLS: &tls.Config{RootCAs: localhostPool},
|
clientTLS: &tls.Config{RootCAs: localhostPool},
|
||||||
serverConnectionHeader: "Upgrade",
|
serverConnectionHeader: "Upgrade",
|
||||||
serverUpgradeHeader: "SPDY/3.1",
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
@ -149,20 +225,46 @@ func TestRoundTripAndNewConnection(t *testing.T) {
|
|||||||
// TODO: Uncomment when fix #19254
|
// TODO: Uncomment when fix #19254
|
||||||
// defer server.Close()
|
// defer server.Close()
|
||||||
|
|
||||||
|
serverURL, err := url.Parse(server.URL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s: Error creating request: %s", k, err)
|
||||||
|
}
|
||||||
req, err := http.NewRequest("GET", server.URL, nil)
|
req, err := http.NewRequest("GET", server.URL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: Error creating request: %s", k, err)
|
t.Fatalf("%s: Error creating request: %s", k, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
spdyTransport := NewRoundTripper(testCase.clientTLS)
|
spdyTransport := NewSpdyRoundTripper(testCase.clientTLS)
|
||||||
|
|
||||||
|
var proxierCalled bool
|
||||||
|
var proxyCalledWithHost string
|
||||||
|
if testCase.proxyServerFunc != nil {
|
||||||
|
proxyHandler := goproxy.NewProxyHttpServer()
|
||||||
|
proxyHandler.OnRequest().HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
|
||||||
|
proxyCalledWithHost = host
|
||||||
|
return goproxy.OkConnect, host
|
||||||
|
})
|
||||||
|
proxy := testCase.proxyServerFunc(proxyHandler)
|
||||||
|
|
||||||
|
spdyTransport.proxier = func(proxierReq *http.Request) (*url.URL, error) {
|
||||||
|
proxyURL, err := url.Parse(proxy.URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
proxierCalled = true
|
||||||
|
return proxyURL, nil
|
||||||
|
}
|
||||||
|
// TODO: Uncomment when fix #19254
|
||||||
|
// defer proxy.Close()
|
||||||
|
}
|
||||||
|
|
||||||
client := &http.Client{Transport: spdyTransport}
|
client := &http.Client{Transport: spdyTransport}
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
var conn httpstream.Connection
|
||||||
t.Fatalf("%s: unexpected error from client.Do: %s", k, err)
|
if err == nil {
|
||||||
|
conn, err = spdyTransport.NewConnection(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := spdyTransport.NewConnection(resp)
|
|
||||||
haveErr := err != nil
|
haveErr := err != nil
|
||||||
if e, a := testCase.shouldError, haveErr; e != a {
|
if e, a := testCase.shouldError, haveErr; e != a {
|
||||||
t.Fatalf("%s: shouldError=%t, got %t: %v", k, e, a, err)
|
t.Fatalf("%s: shouldError=%t, got %t: %v", k, e, a, err)
|
||||||
@ -200,6 +302,15 @@ func TestRoundTripAndNewConnection(t *testing.T) {
|
|||||||
if e, a := "hello", string(b[0:n]); e != a {
|
if e, a := "hello", string(b[0:n]); e != a {
|
||||||
t.Fatalf("%s: expected '%s', got '%s'", k, e, a)
|
t.Fatalf("%s: expected '%s', got '%s'", k, e, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if testCase.proxyServerFunc != nil {
|
||||||
|
if !proxierCalled {
|
||||||
|
t.Fatalf("%s: Expected to use a proxy but proxier in SpdyRoundTripper wasn't called", k)
|
||||||
|
}
|
||||||
|
if proxyCalledWithHost != serverURL.Host {
|
||||||
|
t.Fatalf("%s: Expected to see a call to the proxy for backend %q, got %q", k, serverURL.Host, proxyCalledWithHost)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user