diff --git a/components/engine/api/swagger.yaml b/components/engine/api/swagger.yaml index 10076632cc..fb8710d342 100644 --- a/components/engine/api/swagger.yaml +++ b/components/engine/api/swagger.yaml @@ -3747,18 +3747,22 @@ definitions: description: | HTTP-proxy configured for the daemon. This value is obtained from the [`HTTP_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html) environment variable. + Credentials ([user info component](https://tools.ietf.org/html/rfc3986#section-3.2.1)) in the proxy URL + are masked in the API response. Containers do not automatically inherit this configuration. type: "string" - example: "http://user:pass@proxy.corp.example.com:8080" + example: "http://xxxxx:xxxxx@proxy.corp.example.com:8080" HttpsProxy: description: | HTTPS-proxy configured for the daemon. This value is obtained from the [`HTTPS_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html) environment variable. + Credentials ([user info component](https://tools.ietf.org/html/rfc3986#section-3.2.1)) in the proxy URL + are masked in the API response. Containers do not automatically inherit this configuration. type: "string" - example: "https://user:pass@proxy.corp.example.com:4443" + example: "https://xxxxx:xxxxx@proxy.corp.example.com:4443" NoProxy: description: | Comma-separated list of domain extensions for which no proxy should be diff --git a/components/engine/daemon/info.go b/components/engine/daemon/info.go index 9dcfb95f03..bf84342b54 100644 --- a/components/engine/daemon/info.go +++ b/components/engine/daemon/info.go @@ -2,6 +2,7 @@ package daemon // import "github.com/docker/docker/daemon" import ( "fmt" + "net/url" "os" "runtime" "strings" @@ -61,8 +62,8 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) { ServerVersion: dockerversion.Version, ClusterStore: daemon.configStore.ClusterStore, ClusterAdvertise: daemon.configStore.ClusterAdvertise, - HTTPProxy: sockets.GetProxyEnv("http_proxy"), - HTTPSProxy: sockets.GetProxyEnv("https_proxy"), + HTTPProxy: maskCredentials(sockets.GetProxyEnv("http_proxy")), + HTTPSProxy: maskCredentials(sockets.GetProxyEnv("https_proxy")), NoProxy: sockets.GetProxyEnv("no_proxy"), LiveRestoreEnabled: daemon.configStore.LiveRestoreEnabled, Isolation: daemon.defaultIsolation, @@ -245,3 +246,13 @@ func operatingSystem() string { } return operatingSystem } + +func maskCredentials(rawURL string) string { + parsedURL, err := url.Parse(rawURL) + if err != nil || parsedURL.User == nil { + return rawURL + } + parsedURL.User = url.UserPassword("xxxxx", "xxxxx") + maskedURL := parsedURL.String() + return maskedURL +} diff --git a/components/engine/daemon/info_test.go b/components/engine/daemon/info_test.go new file mode 100644 index 0000000000..076373cba2 --- /dev/null +++ b/components/engine/daemon/info_test.go @@ -0,0 +1,53 @@ +package daemon + +import ( + "testing" + + "gotest.tools/assert" +) + +func TestMaskURLCredentials(t *testing.T) { + tests := []struct { + rawURL string + maskedURL string + }{ + { + rawURL: "", + maskedURL: "", + }, { + rawURL: "invalidURL", + maskedURL: "invalidURL", + }, { + rawURL: "http://proxy.example.com:80/", + maskedURL: "http://proxy.example.com:80/", + }, { + rawURL: "http://USER:PASSWORD@proxy.example.com:80/", + maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/", + }, { + rawURL: "http://PASSWORD:PASSWORD@proxy.example.com:80/", + maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/", + }, { + rawURL: "http://USER:@proxy.example.com:80/", + maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/", + }, { + rawURL: "http://:PASSWORD@proxy.example.com:80/", + maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/", + }, { + rawURL: "http://USER@docker:password@proxy.example.com:80/", + maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/", + }, { + rawURL: "http://USER%40docker:password@proxy.example.com:80/", + maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/", + }, { + rawURL: "http://USER%40docker:pa%3Fsword@proxy.example.com:80/", + maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/", + }, { + rawURL: "http://USER%40docker:pa%3Fsword@proxy.example.com:80/hello%20world", + maskedURL: "http://xxxxx:xxxxx@proxy.example.com:80/hello%20world", + }, + } + for _, test := range tests { + maskedURL := maskCredentials(test.rawURL) + assert.Equal(t, maskedURL, test.maskedURL) + } +}