diff --git a/pkg/minikube/node/config.go b/pkg/minikube/node/config.go index f58839aa5a5c..e7f271a6584a 100644 --- a/pkg/minikube/node/config.go +++ b/pkg/minikube/node/config.go @@ -21,7 +21,9 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "strconv" + "strings" "sync" "github.com/spf13/viper" @@ -39,11 +41,43 @@ import ( "k8s.io/minikube/pkg/util/lock" ) +func maskProxyPassword(v string) string { + parts := strings.Split(v, "=") + // Is it an attribution variable? + if len(parts) == 2 { + key := strings.ToUpper(parts[0]) + // Is it a proxy setting? + if key == "HTTP_PROXY" || key == "HTTPS_PROXY" { + proxyValue := parts[1] + // Proxy variable values SHOULD have a value like + // https(s):// + proxyAddressParts := strings.Split(proxyValue, "://") + if len(proxyAddressParts) == 2 { + proxyURL := "" + proxyURL = proxyAddressParts[1] + // Let's store the username, the URL and and optional port address + pattern := `([^:]+):.+(@[\w\.]+)(:\d+)?` + regexpPattern := regexp.MustCompile(pattern) + matches := regexpPattern.FindStringSubmatch(proxyURL) + mask := "*****" + if len(matches) == 4 { + proxyValue = fmt.Sprintf("%s://%s:%s%s%s", proxyAddressParts[0], matches[1], mask, matches[2], matches[3]) + } else if len(matches) == 3 { + proxyValue = fmt.Sprintf("%s//%s:%s@%s", proxyAddressParts[0], matches[1], mask, matches[2]) + } + } + v = key + "=" + proxyValue + } + } + return v +} + func showVersionInfo(k8sVersion string, cr cruntime.Manager) { version, _ := cr.Version() register.Reg.SetStep(register.PreparingKubernetes) out.Step(cr.Style(), "Preparing Kubernetes {{.k8sVersion}} on {{.runtime}} {{.runtimeVersion}} ...", out.V{"k8sVersion": k8sVersion, "runtime": cr.Name(), "runtimeVersion": version}) for _, v := range config.DockerOpt { + v = maskProxyPassword(v) out.Infof("opt {{.docker_option}}", out.V{"docker_option": v}) } for _, v := range config.DockerEnv { diff --git a/pkg/minikube/node/config_test.go b/pkg/minikube/node/config_test.go new file mode 100644 index 000000000000..c40df55b50a9 --- /dev/null +++ b/pkg/minikube/node/config_test.go @@ -0,0 +1,72 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +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 node + +import ( + "testing" +) + +func Test_maskProxyPassword(t *testing.T) { + type dockerOptTest struct { + input string + output string + } + var tests = []dockerOptTest{ + { + input: "cats", + output: "cats", + }, + { + input: "myDockerOption=value", + output: "myDockerOption=value", + }, + { + input: "http_proxy=http://minikube.sigs.k8s.io", + output: "HTTP_PROXY=http://minikube.sigs.k8s.io", + }, + { + input: "https_proxy=http://jdoe@minikube.sigs.k8s.io:8080", + output: "HTTPS_PROXY=http://jdoe@minikube.sigs.k8s.io:8080", + }, + { + input: "https_proxy=https://mary:iam$Fake!password@minikube.sigs.k8s.io:8080", + output: "HTTPS_PROXY=https://mary:*****@minikube.sigs.k8s.io:8080", + }, + { + input: "http_proxy=http://jdoe:%n0tRe@al:Password!@minikube.sigs.k8s.io:8080", + output: "HTTP_PROXY=http://jdoe:*****@minikube.sigs.k8s.io:8080", + }, + { + input: "http_proxy=http://jo@han:n0tRe@al:&Password!@minikube.sigs.k8s.io:8080", + output: "HTTP_PROXY=http://jo@han:*****@minikube.sigs.k8s.io:8080", + }, + { + input: "http_proxy=http://k@r3n!:an0th3erF@akeP@55word@minikube.sigs.k8s.io", + output: "HTTP_PROXY=http://k@r3n!:*****@minikube.sigs.k8s.io", + }, + { + input: "https_proxy=https://fr@ank5t3in:an0th3erF@akeP@55word@minikube.sigs.k8s.io", + output: "HTTPS_PROXY=https://fr@ank5t3in:*****@minikube.sigs.k8s.io", + }, + } + for _, test := range tests { + got := maskProxyPassword(test.input) + if got != test.output { + t.Errorf("maskProxyPassword(\"%v\"): got %v, expected %v", test.input, got, test.output) + } + } +} diff --git a/pkg/minikube/node/start.go b/pkg/minikube/node/start.go old mode 100644 new mode 100755 index a37ef975d0fc..9047c8b362f1 --- a/pkg/minikube/node/start.go +++ b/pkg/minikube/node/start.go @@ -739,9 +739,15 @@ func validateNetwork(h *host.Host, r command.Runner, imageRepository string) (st out.Styled(style.Internet, "Found network options:") optSeen = true } + k = strings.ToUpper(k) // let's get the key right away to mask password from output + // If http(s)_proxy contains password, let's not splatter on the screen + if k == "HTTP_PROXY" || k == "HTTPS_PROXY" { + pattern := `//(\w+):\w+@` + regexpPattern := regexp.MustCompile(pattern) + v = regexpPattern.ReplaceAllString(v, "//$1:*****@") + } out.Infof("{{.key}}={{.value}}", out.V{"key": k, "value": v}) ipExcluded := proxy.IsIPExcluded(ip) // Skip warning if minikube ip is already in NO_PROXY - k = strings.ToUpper(k) // for http_proxy & https_proxy if (k == "HTTP_PROXY" || k == "HTTPS_PROXY") && !ipExcluded && !warnedOnce { out.WarningT("You appear to be using a proxy, but your NO_PROXY environment does not include the minikube IP ({{.ip_address}}).", out.V{"ip_address": ip}) out.Styled(style.Documentation, "Please see {{.documentation_url}} for more details", out.V{"documentation_url": "https://minikube.sigs.k8s.io/docs/handbook/vpn_and_proxy/"})