diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index e77d86d05c900..49ade9490bd9f 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -99,7 +99,7 @@ func NewAPIServer() *APIServer { RuntimeConfig: make(util.ConfigurationMap), KubeletConfig: client.KubeletConfig{ Port: 10250, - EnableHttps: true, + EnableHttps: false, HTTPTimeout: time.Duration(5) * time.Second, }, } diff --git a/cmd/kube-controller-manager/app/controllermanager.go b/cmd/kube-controller-manager/app/controllermanager.go index 1eecd81ee5b57..13a94d8c2fa19 100644 --- a/cmd/kube-controller-manager/app/controllermanager.go +++ b/cmd/kube-controller-manager/app/controllermanager.go @@ -83,7 +83,7 @@ func NewCMServer() *CMServer { SyncNodeStatus: false, KubeletConfig: client.KubeletConfig{ Port: ports.KubeletPort, - EnableHttps: true, + EnableHttps: false, HTTPTimeout: time.Duration(5) * time.Second, }, } diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go index 53fff33b04a05..2b713a10155a6 100644 --- a/cmd/kubelet/app/server.go +++ b/cmd/kubelet/app/server.go @@ -18,12 +18,10 @@ limitations under the License. package app import ( - "crypto/tls" "fmt" "math/rand" "net" "net/http" - "path" "strconv" "strings" "time" @@ -90,9 +88,6 @@ type KubeletServer struct { NetworkPluginName string CloudProvider string CloudConfigFile string - TLSCertFile string - TLSPrivateKeyFile string - CertDirectory string } // NewKubeletServer will create a new KubeletServer with default values. @@ -120,7 +115,6 @@ func NewKubeletServer() *KubeletServer { ImageGCLowThresholdPercent: 80, NetworkPluginName: "", HostNetworkSources: kubelet.FileSource, - CertDirectory: "/var/run/kubernetes", } } @@ -134,12 +128,6 @@ func (s *KubeletServer) AddFlags(fs *pflag.FlagSet) { fs.BoolVar(&s.EnableServer, "enable_server", s.EnableServer, "Enable the info server") fs.Var(&s.Address, "address", "The IP address for the info server to serve on (set to 0.0.0.0 for all interfaces)") fs.UintVar(&s.Port, "port", s.Port, "The port for the info server to serve on") - fs.StringVar(&s.TLSCertFile, "tls_cert_file", s.TLSCertFile, ""+ - "File containing x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert). "+ - "If --tls_cert_file and --tls_private_key_file are not provided, a self-signed certificate and key "+ - "are generated for the public address and saved to the directory passed to --cert_dir.") - fs.StringVar(&s.TLSPrivateKeyFile, "tls_private_key_file", s.TLSPrivateKeyFile, "File containing x509 private key matching --tls_cert_file.") - fs.StringVar(&s.CertDirectory, "cert_dir", s.CertDirectory, "The directory where the TLS certs are located (by default /var/run/kubernetes)") fs.StringVar(&s.HostnameOverride, "hostname_override", s.HostnameOverride, "If non-empty, will use this string as identification instead of the actual hostname.") fs.StringVar(&s.PodInfraContainerImage, "pod_infra_container_image", s.PodInfraContainerImage, "The image whose network/ipc namespaces containers in each pod will use.") fs.StringVar(&s.DockerEndpoint, "docker_endpoint", s.DockerEndpoint, "If non-empty, use this for the docker endpoint to communicate with") @@ -206,26 +194,6 @@ func (s *KubeletServer) Run(_ []string) error { if err != nil { return err } - - if s.TLSCertFile == "" && s.TLSPrivateKeyFile == "" { - s.TLSCertFile = path.Join(s.CertDirectory, "kubelet.crt") - s.TLSPrivateKeyFile = path.Join(s.CertDirectory, "kubelet.key") - if err := util.GenerateSelfSignedCert(util.GetHostname(s.HostnameOverride), s.TLSCertFile, s.TLSPrivateKeyFile); err != nil { - glog.Fatalf("Unable to generate self signed cert: %v", err) - } - glog.Infof("Using self-signed cert (%s, %s)", s.TLSCertFile, s.TLSPrivateKeyFile) - } - tlsOptions := &kubelet.TLSOptions{ - Config: &tls.Config{ - // Change default from SSLv3 to TLSv1.0 (because of POODLE vulnerability). - MinVersion: tls.VersionTLS10, - // Populate PeerCertificates in requests, but don't yet reject connections without certificates. - ClientAuth: tls.RequestClientCert, - }, - CertFile: s.TLSCertFile, - KeyFile: s.TLSPrivateKeyFile, - } - kcfg := KubeletConfig{ Address: s.Address, AllowPrivileged: s.AllowPrivileged, @@ -257,7 +225,6 @@ func (s *KubeletServer) Run(_ []string) error { NetworkPlugins: ProbeNetworkPlugins(), NetworkPluginName: s.NetworkPluginName, StreamingConnectionIdleTimeout: s.StreamingConnectionIdleTimeout, - TLSOptions: tlsOptions, ImageGCPolicy: imageGCPolicy, Cloud: cloud, } diff --git a/hack/test-cmd.sh b/hack/test-cmd.sh index a91d9f544eac4..75088618f2928 100755 --- a/hack/test-cmd.sh +++ b/hack/test-cmd.sh @@ -48,7 +48,6 @@ ETCD_PORT=${ETCD_PORT:-4001} API_PORT=${API_PORT:-8080} API_HOST=${API_HOST:-127.0.0.1} KUBELET_PORT=${KUBELET_PORT:-10250} -KUBELET_HEALTHZ_PORT=${KUBELET_HEALTHZ_PORT:-10248} CTLRMGR_PORT=${CTLRMGR_PORT:-10252} # Check kubectl @@ -59,31 +58,27 @@ kube::log::status "Starting kubelet in masterless mode" "${KUBE_OUTPUT_HOSTBIN}/kubelet" \ --really_crash_for_testing=true \ --root_dir=/tmp/kubelet.$$ \ - --cert_dir="${TMPDIR:-/tmp/}" \ --docker_endpoint="fake://" \ --hostname_override="127.0.0.1" \ --address="127.0.0.1" \ - --port="$KUBELET_PORT" \ - --healthz_port="${KUBELET_HEALTHZ_PORT}" 1>&2 & + --port="$KUBELET_PORT" 1>&2 & KUBELET_PID=$! -kube::util::wait_for_url "http://127.0.0.1:${KUBELET_HEALTHZ_PORT}/healthz" "kubelet: " +kube::util::wait_for_url "http://127.0.0.1:${KUBELET_PORT}/healthz" "kubelet: " kill ${KUBELET_PID} 1>&2 2>/dev/null kube::log::status "Starting kubelet in masterful mode" "${KUBE_OUTPUT_HOSTBIN}/kubelet" \ --really_crash_for_testing=true \ --root_dir=/tmp/kubelet.$$ \ - --cert_dir="${TMPDIR:-/tmp/}" \ --docker_endpoint="fake://" \ --hostname_override="127.0.0.1" \ --address="127.0.0.1" \ --api_servers="${API_HOST}:${API_PORT}" \ --auth_path="${KUBE_ROOT}/hack/.test-cmd-auth" \ - --port="$KUBELET_PORT" \ - --healthz_port="${KUBELET_HEALTHZ_PORT}" 1>&2 & + --port="$KUBELET_PORT" 1>&2 & KUBELET_PID=$! -kube::util::wait_for_url "http://127.0.0.1:${KUBELET_HEALTHZ_PORT}/healthz" "kubelet: " +kube::util::wait_for_url "http://127.0.0.1:${KUBELET_PORT}/healthz" "kubelet: " # Start kube-apiserver kube::log::status "Starting kube-apiserver" diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index a3d0b56976d62..c92b9b4deda5a 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -139,7 +139,14 @@ func (g *APIGroupVersion) InstallREST(container *restful.Container) error { // TODO: Convert to go-restful func InstallValidator(mux Mux, servers func() map[string]Server) { - mux.Handle("/validate", NewValidator(servers)) + validator, err := NewValidator(servers) + if err != nil { + glog.Errorf("failed to set up validator: %v", err) + return + } + if validator != nil { + mux.Handle("/validate", validator) + } } // TODO: document all handlers diff --git a/pkg/apiserver/validator.go b/pkg/apiserver/validator.go index 368ea66d67feb..037204a540fd4 100644 --- a/pkg/apiserver/validator.go +++ b/pkg/apiserver/validator.go @@ -17,7 +17,6 @@ limitations under the License. package apiserver import ( - "crypto/tls" "encoding/json" "fmt" "io/ioutil" @@ -35,26 +34,21 @@ type httpGet interface { } type Server struct { - Addr string - Port int - Path string - EnableHTTPS bool + Addr string + Port int + Path string } // validator is responsible for validating the cluster and serving type validator struct { // a list of servers to health check servers func() map[string]Server - rt http.RoundTripper + client httpGet } // TODO: can this use pkg/probe/http func (s *Server) check(client httpGet) (probe.Result, string, error) { - scheme := "http://" - if s.EnableHTTPS { - scheme = "https://" - } - resp, err := client.Get(scheme + net.JoinHostPort(s.Addr, strconv.Itoa(s.Port)) + s.Path) + resp, err := client.Get("http://" + net.JoinHostPort(s.Addr, strconv.Itoa(s.Port)) + s.Path) if err != nil { return probe.Unknown, "", err } @@ -87,22 +81,7 @@ func (v *validator) ServeHTTP(w http.ResponseWriter, r *http.Request) { reply := []ServerStatus{} for name, server := range v.servers() { - transport := v.rt - if server.EnableHTTPS { - // TODO(roberthbailey): The servers that use HTTPS are currently the - // kubelets, and we should be using a standard kubelet client library - // to talk to them rather than a separate http client. - transport = &http.Transport{ - Proxy: http.ProxyFromEnvironment, - Dial: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - }).Dial, - TLSHandshakeTimeout: 10 * time.Second, - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - } - status, msg, err := server.check(&http.Client{Transport: transport}) + status, msg, err := server.check(v.client) var errorMsg string if err != nil { errorMsg = err.Error() @@ -124,6 +103,30 @@ func (v *validator) ServeHTTP(w http.ResponseWriter, r *http.Request) { } // NewValidator creates a validator for a set of servers. -func NewValidator(servers func() map[string]Server) http.Handler { - return &validator{servers: servers, rt: http.DefaultTransport} +func NewValidator(servers func() map[string]Server) (http.Handler, error) { + return &validator{ + servers: servers, + client: &http.Client{}, + }, nil +} + +func makeTestValidator(servers map[string]string, get httpGet) (http.Handler, error) { + result := map[string]Server{} + for name, value := range servers { + host, port, err := net.SplitHostPort(value) + if err != nil { + return nil, fmt.Errorf("invalid server spec: %s (%v)", value, err) + } + val, err := strconv.Atoi(port) + if err != nil { + return nil, fmt.Errorf("invalid server spec: %s (%v)", port, err) + } + result[name] = Server{Addr: host, Port: val, Path: "/healthz"} + } + + v, e := NewValidator(func() map[string]Server { return result }) + if e == nil { + v.(*validator).client = get + } + return v, e } diff --git a/pkg/apiserver/validator_test.go b/pkg/apiserver/validator_test.go index 6d0c3a2a0e041..35b991aee0e9a 100644 --- a/pkg/apiserver/validator_test.go +++ b/pkg/apiserver/validator_test.go @@ -21,27 +21,35 @@ import ( "encoding/json" "fmt" "io/ioutil" - "net" "net/http" "net/http/httptest" - "strconv" "testing" "github.com/GoogleCloudPlatform/kubernetes/pkg/probe" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" ) -type fakeRoundTripper struct { +type fakeHttpGet struct { err error resp *http.Response url string } -func (f *fakeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { - f.url = req.URL.String() +func (f *fakeHttpGet) Get(url string) (*http.Response, error) { + f.url = url return f.resp, f.err } +func makeFake(data string, statusCode int, err error) *fakeHttpGet { + return &fakeHttpGet{ + err: err, + resp: &http.Response{ + Body: ioutil.NopCloser(bytes.NewBufferString(data)), + StatusCode: statusCode, + }, + } +} + func TestValidate(t *testing.T) { tests := []struct { err error @@ -58,18 +66,11 @@ func TestValidate(t *testing.T) { s := Server{Addr: "foo.com", Port: 8080, Path: "/healthz"} for _, test := range tests { - fakeRT := &fakeRoundTripper{ - err: test.err, - resp: &http.Response{ - Body: ioutil.NopCloser(bytes.NewBufferString(test.data)), - StatusCode: test.code, - }, - } - fake := &http.Client{Transport: fakeRT} + fake := makeFake(test.data, test.code, test.err) status, data, err := s.check(fake) expect := fmt.Sprintf("http://%s:%d/healthz", s.Addr, s.Port) - if fakeRT.url != expect { - t.Errorf("expected %s, got %s", expect, fakeRT.url) + if fake.url != expect { + t.Errorf("expected %s, got %s", expect, fake.url) } if test.expectErr && err == nil { t.Errorf("unexpected non-error") @@ -86,30 +87,8 @@ func TestValidate(t *testing.T) { } } -func makeTestValidator(servers map[string]string, rt http.RoundTripper) (http.Handler, error) { - result := map[string]Server{} - for name, value := range servers { - host, port, err := net.SplitHostPort(value) - if err != nil { - return nil, fmt.Errorf("invalid server spec: %s (%v)", value, err) - } - val, err := strconv.Atoi(port) - if err != nil { - return nil, fmt.Errorf("invalid server spec: %s (%v)", port, err) - } - result[name] = Server{Addr: host, Port: val, Path: "/healthz"} - } - - return &validator{servers: func() map[string]Server { return result }, rt: rt}, nil -} - func TestValidator(t *testing.T) { - fake := &fakeRoundTripper{ - resp: &http.Response{ - Body: ioutil.NopCloser(bytes.NewBufferString("foo")), - StatusCode: 200, - }, - } + fake := makeFake("foo", 200, nil) validator, err := makeTestValidator(map[string]string{ "foo": "foo.com:80", "bar": "bar.com:8080", @@ -122,6 +101,7 @@ func TestValidator(t *testing.T) { defer testServer.Close() resp, err := http.Get(testServer.URL + "/validatez") + if err != nil { t.Errorf("unexpected error: %v", err) } @@ -133,15 +113,13 @@ func TestValidator(t *testing.T) { if err != nil { t.Errorf("unexpected error: %v", err) } - var status []ServerStatus - if err := json.Unmarshal(data, &status); err != nil { + status := []ServerStatus{} + err = json.Unmarshal(data, &status) + if err != nil { t.Errorf("unexpected error: %v", err) } components := util.StringSet{} for _, s := range status { - if s.Err != "nil" { - t.Errorf("Component %v is unhealthy: %v", s.Component, s.Err) - } components.Insert(s.Component) } if len(status) != 2 || !components.Has("foo") || !components.Has("bar") { diff --git a/pkg/client/kubelet.go b/pkg/client/kubelet.go index 4ad6ef614a294..07e34f8e8e3f0 100644 --- a/pkg/client/kubelet.go +++ b/pkg/client/kubelet.go @@ -75,14 +75,9 @@ type HTTPKubeletClient struct { func NewKubeletClient(config *KubeletConfig) (KubeletClient, error) { transport := http.DefaultTransport - cfg := &Config{TLSClientConfig: config.TLSClientConfig} - if config.EnableHttps { - hasCA := len(config.CAFile) > 0 || len(config.CAData) > 0 - if !hasCA { - cfg.Insecure = true - } - } - tlsConfig, err := TLSConfigFor(cfg) + tlsConfig, err := TLSConfigFor(&Config{ + TLSClientConfig: config.TLSClientConfig, + }) if err != nil { return nil, err } diff --git a/pkg/master/master.go b/pkg/master/master.go index ebcc9b6f9c115..6c55b3208720c 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -561,7 +561,7 @@ func (m *Master) getServersToValidate(c *Config) map[string]apiserver.Server { glog.Errorf("Failed to list minions: %v", err) } for ix, node := range nodes.Items { - serversToValidate[fmt.Sprintf("node-%d", ix)] = apiserver.Server{Addr: node.Name, Port: ports.KubeletPort, Path: "/healthz", EnableHTTPS: true} + serversToValidate[fmt.Sprintf("node-%d", ix)] = apiserver.Server{Addr: node.Name, Port: ports.KubeletPort, Path: "/healthz"} } return serversToValidate }