From 9a7298a3e6663e7d533e4b10fc7e78ef0ab2ee75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20H=C3=B6ffner?= Date: Thu, 12 May 2022 16:53:02 +0200 Subject: [PATCH] volume: mask password in cifs mount error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In managed environment (such as Nomad clusters), users are not always supposed to see credentials used to mount volumes. However, if errors occur (most commonly, misspelled mount paths), the error messages will output the full mount command -- which might contain a username and a password in the case of CIFS mounts. This PR detects password=... when error messages are wrapped and masks them with ********. Closes https://github.com/fsouza/go-dockerclient/issues/905. Closes https://github.com/hashicorp/nomad/issues/12296. Closes https://github.com/moby/moby/issues/43596. Signed-off-by: Sebastian Höffner --- volume/local/local.go | 12 ++++++++++++ volume/local/local_test.go | 19 +++++++++++++++++++ volume/local/local_unix.go | 5 +++++ 3 files changed, 36 insertions(+) diff --git a/volume/local/local.go b/volume/local/local.go index 29e3cc9a54..ec03327a4e 100644 --- a/volume/local/local.go +++ b/volume/local/local.go @@ -366,3 +366,15 @@ func getAddress(opts string) string { } return "" } + +// getPassword finds out a password from options +func getPassword(opts string) string { + optsList := strings.Split(opts, ",") + for i := 0; i < len(optsList); i++ { + if strings.HasPrefix(optsList[i], "password=") { + passwd := strings.SplitN(optsList[i], "=", 2)[1] + return passwd + } + } + return "" +} diff --git a/volume/local/local_test.go b/volume/local/local_test.go index 180ad09380..5e95c74bfe 100644 --- a/volume/local/local_test.go +++ b/volume/local/local_test.go @@ -29,6 +29,25 @@ func TestGetAddress(t *testing.T) { } +func TestGetPassword(t *testing.T) { + cases := map[string]string{ + "password=secret": "secret", + " ": "", + "password=": "", + "password=Tr0ub4dor&3": "Tr0ub4dor&3", + "password=correcthorsebatterystaple": "correcthorsebatterystaple", + "username=moby,password=secret": "secret", + "username=moby,password=secret,addr=11": "secret", + "username=moby,addr=11": "", + } + for optsstring, success := range cases { + v := getPassword(optsstring) + if v != success { + t.Errorf("Test case failed for %s actual: %s expected : %s", optsstring, v, success) + } + } +} + func TestRemove(t *testing.T) { skip.If(t, runtime.GOOS == "windows", "FIXME: investigate why this test fails on CI") rootDir, err := os.MkdirTemp("", "local-volume-test") diff --git a/volume/local/local_unix.go b/volume/local/local_unix.go index 4fdd182544..fcf75314e2 100644 --- a/volume/local/local_unix.go +++ b/volume/local/local_unix.go @@ -143,6 +143,11 @@ func (v *localVolume) mount() error { } } err := mount.Mount(v.opts.MountDevice, v.path, v.opts.MountType, mountOpts) + if err != nil { + if password := getPassword(v.opts.MountOpts); password != "" { + err = errors.New(strings.Replace(err.Error(), "password="+password, "password=********", 1)) + } + } return errors.Wrap(err, "failed to mount local volume") }