Skip to content

Masking proxy credentials from URL when displayed in system info#37934

Merged
thaJeztah merged 1 commit intomoby:masterfrom
dani-docker:esc-879
Oct 4, 2018
Merged

Masking proxy credentials from URL when displayed in system info#37934
thaJeztah merged 1 commit intomoby:masterfrom
dani-docker:esc-879

Conversation

@dani-docker
Copy link
Copy Markdown
Contributor

Signed-off-by: Dani Louca [email protected]

If dockerd is configured to use a proxy https://docs.docker.com/config/daemon/systemd/#httphttps-proxy and if the proxy URL is configured for basic authentication, the SystemInfo (ex: docker info) shows the full proxy URL, including the credentials.

- What I did
This PR masks out the proxy username / password while building the info struct.
To make the solution robust, I used the golang url package to identify the credentials, replace them with asterisks, and rebuild the URL string.
I opted not to use basic strings replacement as it will require to address a bunch of corner cases which makes the solution more complex .

- How I did it

  • convert the proxy URL string into a URL object
  • overwrite the URL object's credentials with asterisks
  • convert the URL to string, (this will result of an encoded string)
  • decode the encoded string , if the decoder fails, simply returns the encoded string

- How to verify it

  • configure your docker to use the following proxy URL http://USER:[email protected]:80/ by following https://docs.docker.com/config/daemon/systemd/#httphttps-proxy
  • run docker info | grep Proxy
    Expected Results:
    Http Proxy: http://*********:*********@proxy.example.com:80/
    Actual Result:
    Http Proxy: http://USER:[email protected]:80/
    - Description for the changelog

- A picture of a cute animal (not mandatory but encouraged)

@dani-docker
Copy link
Copy Markdown
Contributor Author

cc: @thaJeztah

@codecov
Copy link
Copy Markdown

codecov bot commented Sep 29, 2018

Codecov Report

❗ No coverage uploaded for pull request base (master@299015d). Click here to learn what that means.
The diff coverage is 77.77%.

@@            Coverage Diff            @@
##             master   #37934   +/-   ##
=========================================
  Coverage          ?   36.09%           
=========================================
  Files             ?      610           
  Lines             ?    45160           
  Branches          ?        0           
=========================================
  Hits              ?    16302           
  Misses            ?    26621           
  Partials          ?     2237

Copy link
Copy Markdown
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Left some comments inline.

While I can see the reason for masking this information (especially in the output of docker info), I have some concerns; this change could be a breaking change for those that use this information (for whatever reason; perhaps automation, or verifying daemon configuration). This information was added a long time ago (since #11125), so there's definitely a chance that people use this.

Masking this information in just docker info / the /info endpoint limits the exposure, but does not prevent this information from leaking in other ways (this config is obtained from their corresponding HTTP(S)_PROXY environment variables); also taking into account that someone with access to the API already effectively is "root" on the host.

Perhaps not an issue, but worth to double check if we anticipate this being a breaking change.

@thaJeztah
Copy link
Copy Markdown
Member

Oh, we should update the swagger file as well, and update the description for these fields, to describe that credentials are masked when using the endpoint;

moby/api/swagger.yaml

Lines 3760 to 3784 in 7bfec8c

HttpProxy:
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.
Containers do not automatically inherit this configuration.
type: "string"
example: "http://user:[email protected]: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.
Containers do not automatically inherit this configuration.
type: "string"
example: "https://user:[email protected]:4443"
NoProxy:
description: |
Comma-separated list of domain extensions for which no proxy should be
used. This value is obtained from the [`NO_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html)
environment variable.
Containers do not automatically inherit this configuration.
type: "string"
example: "*.local, 169.254/16"

Also may warrant a mention in the API changelog https://github.com/moby/moby/blob/7bfec8cd80c5e2ce548cd7ccf63a35bf60d802d3/docs/api/version-history.md (although it's not versioned, so not sure how to best describe it there)

@dani-docker
Copy link
Copy Markdown
Contributor Author

Oh, we should update the swagger file as well, and update the description for these fields, to describe that credentials are masked when using the endpoint;

moby/api/swagger.yaml

Lines 3760 to 3784 in 7bfec8c

   HttpProxy: 
     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. 

       Containers do not automatically inherit this configuration. 
     type: "string" 
     example: "http://user:[email protected]: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. 

       Containers do not automatically inherit this configuration. 
     type: "string" 
     example: "https://user:[email protected]:4443" 
   NoProxy: 
     description: | 
       Comma-separated list of domain extensions for which no proxy should be 
       used. This value is obtained from the [`NO_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html) 
       environment variable. 

       Containers do not automatically inherit this configuration. 
     type: "string" 
     example: "*.local, 169.254/16" 

Also may warrant a mention in the API changelog https://github.com/moby/moby/blob/7bfec8cd80c5e2ce548cd7ccf63a35bf60d802d3/docs/api/version-history.md (although it's not versioned, so not sure how to best describe it there)

yes, good catch, I will update the swagger

@dani-docker
Copy link
Copy Markdown
Contributor Author

I searched the moby code base and I don't see any place that reads the HTTPProxy or HTTPSProxy straight from the info struct.
I do share your concerns that some 3rd party code might be reading this info from the API and if this is the case, then we'll break their integration; but even if they do, I think it's still not correct design that we share the credentials through the info endpoint.

@dani-docker
Copy link
Copy Markdown
Contributor Author

@thaJeztah
Changed the implementation as suggested and added couple of extra unit tests.
Note: I was under the impression that String() encodes the rest of the URL, not only the credentials part, but running few tests showed that it's not the case; by using xxxxx instead of ***** , we no longer need to worry about decoding/encoding the result of String()

Another note, while testing different URLs variations;
I noticed that the url method parse will fail to parse out credentials that are not escaped.
for example running parse on this url http://USER@docker:[email protected]:80/hello world , will result of no password or username set, this will cause the masking URL to look like this http://xxxxx:xxxxx@docker:[email protected]:80/hello world

The expectation here is that user should encode those type of strings when they configure HTTP(s) Proxy, otherwise, their dial will also fail as the core logic uses the same parse function

@dani-docker
Copy link
Copy Markdown
Contributor Author

Also updated the swagger but not sure how to deal with the history file without having an API version

Copy link
Copy Markdown
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@thaJeztah
Copy link
Copy Markdown
Member

It's green! merging

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants