From ed550a05517107b7621a8d8f9c560e08e6ca4b34 Mon Sep 17 00:00:00 2001 From: Renato Moutinho Date: Wed, 23 Aug 2023 21:43:36 -0300 Subject: [PATCH 1/3] Masking http(s)_proxy password from output. --- pkg/minikube/node/config.go | 12 ++++++++++++ pkg/minikube/node/start.go | 8 +++++++- 2 files changed, 19 insertions(+), 1 deletion(-) mode change 100644 => 100755 pkg/minikube/node/start.go diff --git a/pkg/minikube/node/config.go b/pkg/minikube/node/config.go index f58839aa5a5c..c1635fa29e86 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" @@ -47,6 +49,16 @@ func showVersionInfo(k8sVersion string, cr cruntime.Manager) { out.Infof("opt {{.docker_option}}", out.V{"docker_option": v}) } for _, v := range config.DockerEnv { + parts := strings.Split(v, "=") + if len(parts) == 2 { + key := strings.ToUpper(parts[0]) + if key == "HTTP_PROXY" || key == "HTTPS_PROXY" { + pattern := `//(\w+):\w+@` + regexpPattern := regexp.MustCompile(pattern) + value := regexpPattern.ReplaceAllString(parts[1], "//$1:*****@") + v = key + "=" + value + } + } out.Infof("env {{.docker_env}}", out.V{"docker_env": v}) } } diff --git a/pkg/minikube/node/start.go b/pkg/minikube/node/start.go old mode 100644 new mode 100755 index fd4c00921b4e..b8be4fc9e5c2 --- a/pkg/minikube/node/start.go +++ b/pkg/minikube/node/start.go @@ -723,9 +723,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/"}) From 5aeb4a5dc6e4d721af8679a5177024ddaea5cef6 Mon Sep 17 00:00:00 2001 From: Renato Moutinho Date: Sat, 2 Sep 2023 00:37:46 -0300 Subject: [PATCH 2/3] Moved mask to a func and added test case. --- pkg/minikube/node/config.go | 25 +++++++------ pkg/minikube/node/config_test.go | 60 ++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 pkg/minikube/node/config_test.go diff --git a/pkg/minikube/node/config.go b/pkg/minikube/node/config.go index c1635fa29e86..829e8d4bec9a 100644 --- a/pkg/minikube/node/config.go +++ b/pkg/minikube/node/config.go @@ -41,24 +41,29 @@ import ( "k8s.io/minikube/pkg/util/lock" ) +func maskProxyPassword(v string) string { + parts := strings.Split(v, "=") + if len(parts) == 2 { + key := strings.ToUpper(parts[0]) + if key == "HTTP_PROXY" || key == "HTTPS_PROXY" { + pattern := `//([^:]+):[^\@]+@` + regexpPattern := regexp.MustCompile(pattern) + value := regexpPattern.ReplaceAllString(parts[1], "//$1:*****@") + v = key + "=" + value + } + } + 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 { - parts := strings.Split(v, "=") - if len(parts) == 2 { - key := strings.ToUpper(parts[0]) - if key == "HTTP_PROXY" || key == "HTTPS_PROXY" { - pattern := `//(\w+):\w+@` - regexpPattern := regexp.MustCompile(pattern) - value := regexpPattern.ReplaceAllString(parts[1], "//$1:*****@") - v = key + "=" + value - } - } out.Infof("env {{.docker_env}}", out.V{"docker_env": v}) } } diff --git a/pkg/minikube/node/config_test.go b/pkg/minikube/node/config_test.go new file mode 100644 index 000000000000..7bd094f6aff1 --- /dev/null +++ b/pkg/minikube/node/config_test.go @@ -0,0 +1,60 @@ +/* +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://myproxy.company.com", + output: "HTTP_PROXY=http://myproxy.company.com", + }, + { + input: "https_proxy=http://jdoe@myproxy.company.com:8080", + output: "HTTPS_PROXY=http://jdoe@myproxy.company.com:8080", + }, + { + input: "https_proxy=https://mary:am$uT8zB(rP@myproxy.company.com:8080", + output: "HTTPS_PROXY=https://mary:*****@myproxy.company.com:8080", + }, + { + input: "http_proxy=http://jdoe:mPu3z9uT#!@myproxy.company.com:8080", + output: "HTTP_PROXY=http://jdoe:*****@myproxy.company.com:8080", + }, + } + 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) + } + } +} From df10b09dbbeac24ae88706f418e89fa15ebc408d Mon Sep 17 00:00:00 2001 From: Renato Moutinho Date: Tue, 5 Sep 2023 22:17:15 -0300 Subject: [PATCH 3/3] Increasded regex robustness --- pkg/minikube/node/config.go | 25 +++++++++++++++++++++---- pkg/minikube/node/config_test.go | 28 ++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/pkg/minikube/node/config.go b/pkg/minikube/node/config.go index 829e8d4bec9a..e7f271a6584a 100644 --- a/pkg/minikube/node/config.go +++ b/pkg/minikube/node/config.go @@ -43,13 +43,30 @@ import ( 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" { - pattern := `//([^:]+):[^\@]+@` - regexpPattern := regexp.MustCompile(pattern) - value := regexpPattern.ReplaceAllString(parts[1], "//$1:*****@") - v = key + "=" + value + 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 diff --git a/pkg/minikube/node/config_test.go b/pkg/minikube/node/config_test.go index 7bd094f6aff1..c40df55b50a9 100644 --- a/pkg/minikube/node/config_test.go +++ b/pkg/minikube/node/config_test.go @@ -35,20 +35,32 @@ func Test_maskProxyPassword(t *testing.T) { output: "myDockerOption=value", }, { - input: "http_proxy=http://myproxy.company.com", - output: "HTTP_PROXY=http://myproxy.company.com", + input: "http_proxy=http://minikube.sigs.k8s.io", + output: "HTTP_PROXY=http://minikube.sigs.k8s.io", }, { - input: "https_proxy=http://jdoe@myproxy.company.com:8080", - output: "HTTPS_PROXY=http://jdoe@myproxy.company.com:8080", + 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:am$uT8zB(rP@myproxy.company.com:8080", - output: "HTTPS_PROXY=https://mary:*****@myproxy.company.com: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:mPu3z9uT#!@myproxy.company.com:8080", - output: "HTTP_PROXY=http://jdoe:*****@myproxy.company.com: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 {