diff --git a/contrib/completions/bash/kubectl b/contrib/completions/bash/kubectl index 9bb84b5533e..bfb00cfa5c8 100644 --- a/contrib/completions/bash/kubectl +++ b/contrib/completions/bash/kubectl @@ -595,6 +595,8 @@ _kubectl_proxy() two_word_flags+=("-p") flags+=("--reject-methods=") flags+=("--reject-paths=") + flags+=("--unix-socket=") + two_word_flags+=("-u") flags+=("--www=") two_word_flags+=("-w") flags+=("--www-prefix=") diff --git a/docs/man/man1/kubectl-proxy.1 b/docs/man/man1/kubectl-proxy.1 index 3200c91c131..d07777c7bed 100644 --- a/docs/man/man1/kubectl-proxy.1 +++ b/docs/man/man1/kubectl-proxy.1 @@ -52,7 +52,7 @@ The above lets you 'curl localhost:8001/custom/api/v1/pods' .PP \fB\-\-disable\-filter\fP=false - If true, disable request filtering in the proxy. This is dangerous, and can leave you vulnerable to XSRF attacks. Use with caution. + If true, disable request filtering in the proxy. This is dangerous, and can leave you vulnerable to XSRF attacks, when used with an accessible port. .PP \fB\-h\fP, \fB\-\-help\fP=false @@ -70,6 +70,10 @@ The above lets you 'curl localhost:8001/custom/api/v1/pods' \fB\-\-reject\-paths\fP="^/api/.\fI/exec,^/api/.\fP/run" Regular expression for paths that the proxy should reject. +.PP +\fB\-u\fP, \fB\-\-unix\-socket\fP="" + Unix socket on which to run the proxy. + .PP \fB\-w\fP, \fB\-\-www\fP="" Also serve static files from the given directory under the specified prefix. diff --git a/docs/user-guide/kubectl/kubectl_proxy.md b/docs/user-guide/kubectl/kubectl_proxy.md index 60fcb0274c1..82e79aaf4fa 100644 --- a/docs/user-guide/kubectl/kubectl_proxy.md +++ b/docs/user-guide/kubectl/kubectl_proxy.md @@ -80,11 +80,12 @@ $ kubectl proxy --api-prefix=/k8s-api --accept-hosts="^localhost$,^127\\.0\\.0\\.1$,^\\[::1\\]$": Regular expression for hosts that the proxy should accept. --accept-paths="^/.*": Regular expression for paths that the proxy should accept. --api-prefix="/api/": Prefix to serve the proxied API under. - --disable-filter=false: If true, disable request filtering in the proxy. This is dangerous, and can leave you vulnerable to XSRF attacks. Use with caution. + --disable-filter=false: If true, disable request filtering in the proxy. This is dangerous, and can leave you vulnerable to XSRF attacks, when used with an accessible port. -h, --help=false: help for proxy -p, --port=8001: The port on which to run the proxy. Set to 0 to pick a random port. --reject-methods="POST,PUT,PATCH": Regular expression for HTTP methods that the proxy should reject. --reject-paths="^/api/.*/exec,^/api/.*/run": Regular expression for paths that the proxy should reject. + -u, --unix-socket="": Unix socket on which to run the proxy. -w, --www="": Also serve static files from the given directory under the specified prefix. -P, --www-prefix="/static/": Prefix to serve static files under, if static file directory is specified. ``` @@ -122,7 +123,7 @@ $ kubectl proxy --api-prefix=/k8s-api * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra at 2015-07-14 00:11:42.957150329 +0000 UTC +###### Auto generated by spf13/cobra at 2015-08-04 15:27:44.354669483 +0000 UTC diff --git a/pkg/kubectl/cmd/proxy.go b/pkg/kubectl/cmd/proxy.go index 21c473c3d8d..55716f32afb 100644 --- a/pkg/kubectl/cmd/proxy.go +++ b/pkg/kubectl/cmd/proxy.go @@ -17,8 +17,10 @@ limitations under the License. package cmd import ( + "errors" "fmt" "io" + "net" "strings" "github.com/golang/glog" @@ -28,6 +30,7 @@ import ( ) const ( + default_port = 8001 proxy_example = `// Run a proxy to kubernetes apiserver on port 8011, serving static content from ./local/www/ $ kubectl proxy --port=8011 --www=./local/www/ @@ -73,14 +76,20 @@ The above lets you 'curl localhost:8001/custom/api/v1/pods' cmd.Flags().String("reject-paths", kubectl.DefaultPathRejectRE, "Regular expression for paths that the proxy should reject.") cmd.Flags().String("accept-hosts", kubectl.DefaultHostAcceptRE, "Regular expression for hosts that the proxy should accept.") cmd.Flags().String("reject-methods", kubectl.DefaultMethodRejectRE, "Regular expression for HTTP methods that the proxy should reject.") - cmd.Flags().IntP("port", "p", 8001, "The port on which to run the proxy. Set to 0 to pick a random port.") - cmd.Flags().Bool("disable-filter", false, "If true, disable request filtering in the proxy. This is dangerous, and can leave you vulnerable to XSRF attacks. Use with caution.") + cmd.Flags().IntP("port", "p", default_port, "The port on which to run the proxy. Set to 0 to pick a random port.") + cmd.Flags().Bool("disable-filter", false, "If true, disable request filtering in the proxy. This is dangerous, and can leave you vulnerable to XSRF attacks, when used with an accessible port.") + cmd.Flags().StringP("unix-socket", "u", "", "Unix socket on which to run the proxy.") return cmd } func RunProxy(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command) error { + path := cmdutil.GetFlagString(cmd, "unix-socket") port := cmdutil.GetFlagInt(cmd, "port") + if port != default_port && path != "" { + return errors.New("Don't specify both --unix-socket and --port") + } + clientConfig, err := f.ClientConfig() if err != nil { return err @@ -101,18 +110,22 @@ func RunProxy(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command) error { AcceptHosts: kubectl.MakeRegexpArrayOrDie(cmdutil.GetFlagString(cmd, "accept-hosts")), } if cmdutil.GetFlagBool(cmd, "disable-filter") { - glog.Warning("Request filter disabled, your proxy is vulnerable to XSRF attacks, please be cautious") + if path == "" { + glog.Warning("Request filter disabled, your proxy is vulnerable to XSRF attacks, please be cautious") + } filter = nil } - server, err := kubectl.NewProxyServer(port, cmdutil.GetFlagString(cmd, "www"), apiProxyPrefix, staticPrefix, filter, clientConfig) - if err != nil { - return err - } + server, err := kubectl.NewProxyServer(cmdutil.GetFlagString(cmd, "www"), apiProxyPrefix, staticPrefix, filter, clientConfig) // Separate listening from serving so we can report the bound port - // when it is chosen by os (port == 0) - l, err := server.Listen() + // when it is chosen by os (eg: port == 0) + var l net.Listener + if path == "" { + l, err = server.Listen(port) + } else { + l, err = server.ListenUnix(path) + } if err != nil { glog.Fatal(err) } diff --git a/pkg/kubectl/proxy_server.go b/pkg/kubectl/proxy_server.go index d1e0e9bfdee..4935a24dc37 100644 --- a/pkg/kubectl/proxy_server.go +++ b/pkg/kubectl/proxy_server.go @@ -22,12 +22,14 @@ import ( "net/http" "net/http/httputil" "net/url" + "os" "regexp" "strings" "time" "github.com/golang/glog" "k8s.io/kubernetes/pkg/client" + "k8s.io/kubernetes/pkg/util" ) const ( @@ -139,13 +141,12 @@ func (f *FilterServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { // ProxyServer is a http.Handler which proxies Kubernetes APIs to remote API server. type ProxyServer struct { handler http.Handler - port int } // NewProxyServer creates and installs a new ProxyServer. // It automatically registers the created ProxyServer to http.DefaultServeMux. // 'filter', if non-nil, protects requests to the api only. -func NewProxyServer(port int, filebase string, apiProxyPrefix string, staticPrefix string, filter *FilterServer, cfg *client.Config) (*ProxyServer, error) { +func NewProxyServer(filebase string, apiProxyPrefix string, staticPrefix string, filter *FilterServer, cfg *client.Config) (*ProxyServer, error) { host := cfg.Host if !strings.HasSuffix(host, "/") { host = host + "/" @@ -174,12 +175,26 @@ func NewProxyServer(port int, filebase string, apiProxyPrefix string, staticPref // serving their working directory by default. mux.Handle(staticPrefix, newFileHandler(staticPrefix, filebase)) } - return &ProxyServer{handler: mux, port: port}, nil + return &ProxyServer{handler: mux}, nil } // Listen is a simple wrapper around net.Listen. -func (s *ProxyServer) Listen() (net.Listener, error) { - return net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", s.port)) +func (s *ProxyServer) Listen(port int) (net.Listener, error) { + return net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) +} + +// ListenUnix does net.Listen for a unix socket +func (s *ProxyServer) ListenUnix(path string) (net.Listener, error) { + // Remove any socket, stale or not, but fall through for other files + fi, err := os.Stat(path) + if err == nil && (fi.Mode()&os.ModeSocket) != 0 { + os.Remove(path) + } + // Default to only user accessible socket, caller can open up later if desired + oldmask, _ := util.Umask(0077) + l, err := net.Listen("unix", path) + util.Umask(oldmask) + return l, err } // Serve starts the server using given listener, loops forever. diff --git a/pkg/kubectl/proxy_server_test.go b/pkg/kubectl/proxy_server_test.go index a8d44e14cb0..43b29f25165 100644 --- a/pkg/kubectl/proxy_server_test.go +++ b/pkg/kubectl/proxy_server_test.go @@ -287,7 +287,7 @@ func TestPathHandling(t *testing.T) { for _, item := range table { func() { - p, err := NewProxyServer(0, "", item.prefix, "/not/used/for/this/test", nil, cc) + p, err := NewProxyServer("", item.prefix, "/not/used/for/this/test", nil, cc) if err != nil { t.Fatalf("%#v: %v", item, err) }