From 4da751f5d78d43ae4fafa0e8dcfe396bc6127e07 Mon Sep 17 00:00:00 2001 From: Martin Schimandl Date: Fri, 2 Oct 2020 12:13:08 +0200 Subject: [PATCH 1/3] Make none driver work as regular user (use sudo on demand) --- cmd/minikube/cmd/start.go | 11 ++++++ pkg/minikube/command/exec_runner.go | 47 ++++++++++++++++++++++--- pkg/minikube/driver/driver.go | 2 +- pkg/minikube/registry/drvs/none/none.go | 6 +--- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index 909b37d7340e..ee5d3a0fbf0b 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -790,6 +790,17 @@ func validateUser(drvName string) { exit.Message(reason.DrvNeedsRoot, `The "{{.driver_name}}" driver requires root privileges. Please run minikube using 'sudo -E minikube start --driver={{.driver_name}}'.`, out.V{"driver_name": drvName}) } + // None driver works with root and without root on Linux + if runtime.GOOS == "linux" && drvName == driver.None { + if !viper.GetBool(interactive) { + test := exec.Command("sudo", "-n", "echo", "-n") + if err := test.Run(); err != nil { + exit.Message(reason.DrvNeedsRoot, `sudo requires a password, and --interactive=false`) + } + } + return + } + // If root is required, or we are not root, exit early if driver.NeedsRoot(drvName) || u.Uid != "0" { return diff --git a/pkg/minikube/command/exec_runner.go b/pkg/minikube/command/exec_runner.go index 7b5b61acdbf7..6e5caf5708a2 100644 --- a/pkg/minikube/command/exec_runner.go +++ b/pkg/minikube/command/exec_runner.go @@ -20,10 +20,12 @@ import ( "bytes" "fmt" "io" + "io/ioutil" "os" "os/exec" "path" "path/filepath" + "runtime" "strconv" "time" @@ -85,11 +87,11 @@ func (*execRunner) RunCmd(cmd *exec.Cmd) (*RunResult, error) { } // Copy copies a file and its permissions -func (*execRunner) Copy(f assets.CopyableFile) error { +func (e *execRunner) Copy(f assets.CopyableFile) error { dst := path.Join(f.GetTargetDir(), f.GetTargetName()) if _, err := os.Stat(dst); err == nil { klog.Infof("found %s, removing ...", dst) - if err := os.Remove(dst); err != nil { + if err := e.Remove(f); err != nil { return errors.Wrapf(err, "error removing file %s", dst) } } @@ -105,12 +107,47 @@ func (*execRunner) Copy(f assets.CopyableFile) error { return errors.Wrapf(err, "error converting permissions %s to integer", f.GetPermissions()) } - return writeFile(dst, f, os.FileMode(perms)) + switch runtime.GOOS { + case "linux": + // write to temp location ... + tmpfile, err := ioutil.TempFile("", "minikube") + if err != nil { + return errors.Wrapf(err, "error creating tempfile") + } + defer os.Remove(tmpfile.Name()) + err = writeFile(tmpfile.Name(), f, os.FileMode(perms)) + if err != nil { + return errors.Wrapf(err, "error writing to tempfile %s", tmpfile.Name()) + } + + // ... then use sudo to move to target ... + _, err = e.RunCmd(exec.Command("sudo", "cp", "-a", tmpfile.Name(), dst)) + if err != nil { + return errors.Wrapf(err, "error copying tempfile %s to dst %s", tmpfile.Name(), dst) + } + + // ... then fix file permission that should have been fine because of "cp -a" + err = os.Chmod(dst, os.FileMode(perms)) + return err + + default: + return writeFile(dst, f, os.FileMode(perms)) + } + } // Remove removes a file -func (*execRunner) Remove(f assets.CopyableFile) error { +func (e *execRunner) Remove(f assets.CopyableFile) error { dst := filepath.Join(f.GetTargetDir(), f.GetTargetName()) klog.Infof("rm: %s", dst) - return os.Remove(dst) + if err := os.Remove(dst); err != nil { + if !os.IsPermission(err) { + return err + } + _, err = e.RunCmd(exec.Command("sudo", "rm", "-f", dst)) + if err != nil { + return err + } + } + return nil } diff --git a/pkg/minikube/driver/driver.go b/pkg/minikube/driver/driver.go index 8d876f1c8302..3bde60e3165d 100644 --- a/pkg/minikube/driver/driver.go +++ b/pkg/minikube/driver/driver.go @@ -143,7 +143,7 @@ func BareMetal(name string) bool { // NeedsRoot returns true if driver needs to run with root privileges func NeedsRoot(name string) bool { - return name == None + return false } // NeedsPortForward returns true if driver is unable provide direct IP connectivity diff --git a/pkg/minikube/registry/drvs/none/none.go b/pkg/minikube/registry/drvs/none/none.go index 7afae87987df..ae473723c248 100644 --- a/pkg/minikube/registry/drvs/none/none.go +++ b/pkg/minikube/registry/drvs/none/none.go @@ -61,14 +61,10 @@ func status() registry.State { return registry.State{Running: true, Error: err, Installed: false, Fix: "Install docker", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/none/"} } - u, err := user.Current() + _, err = user.Current() if err != nil { return registry.State{Running: true, Error: err, Healthy: false, Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/none/"} } - if u.Uid != "0" { - return registry.State{Error: fmt.Errorf("the 'none' driver must be run as the root user"), Healthy: false, Fix: "For non-root usage, try the newer 'docker' driver", Installed: true} - } - return registry.State{Installed: true, Healthy: true} } From 427daf6e792dde5dfb4a8c2d8703cb0d6b0d2397 Mon Sep 17 00:00:00 2001 From: Martin Schimandl Date: Sun, 1 Nov 2020 15:08:52 +0100 Subject: [PATCH 2/3] Check if user has sudo permissions --- pkg/minikube/registry/drvs/none/none.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/minikube/registry/drvs/none/none.go b/pkg/minikube/registry/drvs/none/none.go index ae473723c248..6ca39eb10a1b 100644 --- a/pkg/minikube/registry/drvs/none/none.go +++ b/pkg/minikube/registry/drvs/none/none.go @@ -61,10 +61,16 @@ func status() registry.State { return registry.State{Running: true, Error: err, Installed: false, Fix: "Install docker", Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/none/"} } - _, err = user.Current() + u, err := user.Current() if err != nil { return registry.State{Running: true, Error: err, Healthy: false, Doc: "https://minikube.sigs.k8s.io/docs/reference/drivers/none/"} } + if u.Uid != "0" { + test := exec.Command("sudo", "-n", "echo", "-n") + if err := test.Run(); err != nil { + return registry.State{Error: fmt.Errorf("running the 'none' driver as a regular user requires sudo permissions"), Healthy: false} + } + } return registry.State{Installed: true, Healthy: true} } From 64729fb03ae63c1826ece52fc4b05d6ddd685c26 Mon Sep 17 00:00:00 2001 From: Martin Schimandl Date: Thu, 26 Nov 2020 19:54:05 +0100 Subject: [PATCH 3/3] Remove function 'NeedsRoot' --- cmd/minikube/cmd/start.go | 8 ++------ pkg/minikube/driver/driver.go | 5 ----- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index ee5d3a0fbf0b..324d6d9d3243 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -786,10 +786,6 @@ func validateUser(drvName string) { useForce := viper.GetBool(force) - if driver.NeedsRoot(drvName) && u.Uid != "0" && !useForce { - exit.Message(reason.DrvNeedsRoot, `The "{{.driver_name}}" driver requires root privileges. Please run minikube using 'sudo -E minikube start --driver={{.driver_name}}'.`, out.V{"driver_name": drvName}) - } - // None driver works with root and without root on Linux if runtime.GOOS == "linux" && drvName == driver.None { if !viper.GetBool(interactive) { @@ -801,8 +797,8 @@ func validateUser(drvName string) { return } - // If root is required, or we are not root, exit early - if driver.NeedsRoot(drvName) || u.Uid != "0" { + // If we are not root, exit early + if u.Uid != "0" { return } diff --git a/pkg/minikube/driver/driver.go b/pkg/minikube/driver/driver.go index 3bde60e3165d..c7b6a6c26c3d 100644 --- a/pkg/minikube/driver/driver.go +++ b/pkg/minikube/driver/driver.go @@ -141,11 +141,6 @@ func BareMetal(name string) bool { return name == None || name == Mock } -// NeedsRoot returns true if driver needs to run with root privileges -func NeedsRoot(name string) bool { - return false -} - // NeedsPortForward returns true if driver is unable provide direct IP connectivity func NeedsPortForward(name string) bool { // Docker for Desktop