New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use an encrypted client certificate to connect to a docker daemon #31364

Merged
merged 2 commits into from Apr 10, 2017

Conversation

@adshmh
Contributor

adshmh commented Feb 26, 2017

An encrypted client certificate can be used to connect to a docker daemon.

Signed-off-by: Arash Deshmeh adeshmeh@ca.ibm.com

- What I did
This is a first attempt at fixing #30935. As discussed on #30935, the first draft of the PR includes changes to vendor repositories (docker/go-connections and docker/notary), to allow review of all the required changes. These will be submitted as PRs on corresponding repos after the approval of
the changes.

- How I did it

  • Added code to go-connections repo to make use of existing functionaliy in notary for decrypting private keys.
  • Added code for passing function for getting password from the client to the go-connections (and to notary)
    - added this as an option in tlsconfig options.
  • Added code for the functionality to be enabled only if a client-specific flag is present (named it 'tlsgetpass' for now)

- How to verify it

  • To reproduce, as shown in #30935, follow the tutorial here : https://docs.docker.com/engine/security/https/ , but generate an encrypted private key:
    $ openssl genrsa -aes256 -out key.pem 4096

  • Current behavior: running a docker command (include -H ) will result in an error, e.g.:
    $ docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem version
    Could not load X509 key pair: tls: failed to parse private key. Make sure the key is not encrypted

  • With this PR (include -H for host/port)
    $ docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem version
    Enter passphrase for key with ID private: ******** (passphrase for the private key should be entered)
    Client:
    Version: 17.04.0-dev
    API version: 1.26 (downgraded from 1.27)
    Go version: go1.7.5
    Git commit: ffc70d2
    Built: Sat Feb 25 20:14:54 2017
    OS/Arch: linux/amd64

Server:
Version: 1.14.0-dev
API version: 1.26 (minimum version 1.12)
Go version: go1.7.3
Git commit: 1b63529
Built: Wed Nov 30 08:16:55 2016
OS/Arch: linux/amd64
Experimental: false

- Description for the changelog
Encrypted client certificate can be used to connect to a docker daemon.

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

@adshmh

This comment has been minimized.

Show comment
Hide comment
@adshmh

adshmh Feb 26, 2017

Contributor

note: the reason for introducing --tlsgetpass command option is to avoid breaking existing uses (e.g. without this option, a command with incorrect private key will not fail, instead will show a prompt for the passphrase). Some integration tests will also fail without this option (e.g. any test that passes an intentionally invalid key).

Contributor

adshmh commented Feb 26, 2017

note: the reason for introducing --tlsgetpass command option is to avoid breaking existing uses (e.g. without this option, a command with incorrect private key will not fail, instead will show a prompt for the passphrase). Some integration tests will also fail without this option (e.g. any test that passes an intentionally invalid key).

@thaJeztah

This comment has been minimized.

Show comment
Hide comment
@thaJeztah
Member

thaJeztah commented Feb 28, 2017

ping @cyli @endophage PTAL

@cyli

This comment has been minimized.

Show comment
Hide comment
@cyli

cyli Mar 1, 2017

Contributor

Thanks for working on this @adshmh - I have a couple comments about where things should be called from, etc., but appreciate the draft and look forward to the functionality!

Contributor

cyli commented Mar 1, 2017

Thanks for working on this @adshmh - I have a couple comments about where things should be called from, etc., but appreciate the draft and look forward to the functionality!

Show outdated Hide outdated cmd/docker/docker.go Outdated
Show outdated Hide outdated cli/command/cli.go Outdated
Show outdated Hide outdated cli/command/cli.go Outdated
@aaronlehmann

This comment has been minimized.

Show comment
Hide comment
@aaronlehmann

aaronlehmann Mar 13, 2017

Contributor

ping @cyli @endophage: It looks like the PR has been updated to address your comments. Can you take a look?

Contributor

aaronlehmann commented Mar 13, 2017

ping @cyli @endophage: It looks like the PR has been updated to address your comments. Can you take a look?

@adshmh

This comment has been minimized.

Show comment
Hide comment
@adshmh

adshmh Mar 13, 2017

Contributor

@aaronlehmann, @endophage Thank you for the reviews.

  • I will update the PR to use errors.Wrap.
  • Regarding the change to vendored file, the idea was to initially use a single PR to show all the changes in one place for easier review, and submit separate PRs to get the changes committed to corresponding repos one all changes are acceptable. I will start submitting the PR on go-connections once the changes are approved.
Contributor

adshmh commented Mar 13, 2017

@aaronlehmann, @endophage Thank you for the reviews.

  • I will update the PR to use errors.Wrap.
  • Regarding the change to vendored file, the idea was to initially use a single PR to show all the changes in one place for easier review, and submit separate PRs to get the changes committed to corresponding repos one all changes are acceptable. I will start submitting the PR on go-connections once the changes are approved.
@aaronlehmann

This comment has been minimized.

Show comment
Hide comment
@aaronlehmann

aaronlehmann Mar 16, 2017

Contributor

Design LGTM

Contributor

aaronlehmann commented Mar 16, 2017

Design LGTM

@aaronlehmann

This comment has been minimized.

Show comment
Hide comment
@aaronlehmann

aaronlehmann Mar 16, 2017

Contributor

Can you please open a PR for go-connections?

Contributor

aaronlehmann commented Mar 16, 2017

Can you please open a PR for go-connections?

@adshmh

This comment has been minimized.

Show comment
Hide comment
@adshmh

adshmh Mar 16, 2017

Contributor

Thank you for the review. I will open the PR for go-connections.
Possibly for a separate PR, do you recommend removing the "errors" reference from cli/command/cli.go and changing the single reference to it to use pkg/errors as well?
(then the 'perrors' alias that I used for pkg/errors can also be removed)

Contributor

adshmh commented Mar 16, 2017

Thank you for the review. I will open the PR for go-connections.
Possibly for a separate PR, do you recommend removing the "errors" reference from cli/command/cli.go and changing the single reference to it to use pkg/errors as well?
(then the 'perrors' alias that I used for pkg/errors can also be removed)

@aaronlehmann

This comment has been minimized.

Show comment
Hide comment
@aaronlehmann

aaronlehmann Mar 16, 2017

Contributor

Possibly for a separate PR, do you recommend removing the "errors" reference from cli/command/cli.go and changing the single reference to it to use pkg/errors as well?
(then the 'perrors' alias that I used for pkg/errors can also be removed)

Yes. You can do it in this PR.

Contributor

aaronlehmann commented Mar 16, 2017

Possibly for a separate PR, do you recommend removing the "errors" reference from cli/command/cli.go and changing the single reference to it to use pkg/errors as well?
(then the 'perrors' alias that I used for pkg/errors can also be removed)

Yes. You can do it in this PR.

@thaJeztah

This comment has been minimized.

Show comment
Hide comment
@thaJeztah

thaJeztah Mar 17, 2017

Member

@aaronlehmann looks like the PR was updated, PTAL

Member

thaJeztah commented Mar 17, 2017

@aaronlehmann looks like the PR was updated, PTAL

@aaronlehmann

This comment has been minimized.

Show comment
Hide comment
@aaronlehmann

aaronlehmann Mar 17, 2017

Contributor

@thaJeztah: Still waiting for vendoring

Contributor

aaronlehmann commented Mar 17, 2017

@thaJeztah: Still waiting for vendoring

@vdemeester

This comment has been minimized.

Show comment
Hide comment
@vdemeester

vdemeester Mar 31, 2017

Member

ping @adshmh docker/go-connections#35 is merged, can you rebase your PR and add a commit to vendor this commit of go-connections ?

Member

vdemeester commented Mar 31, 2017

ping @adshmh docker/go-connections#35 is merged, can you rebase your PR and add a commit to vendor this commit of go-connections ?

@endophage

This comment has been minimized.

Show comment
Hide comment
@endophage

endophage Mar 31, 2017

Contributor

Something I should bring to everyone's attention as a consideration before merging this PR. We're actually planning to deprecate the encrypted PEMs in notary in place of PKCS#8 in the very near future (next 6-8 weeks). We didn't realize at the time but encrypted PEMs use md5 for deriving keys from passwords and we want to ultimately no longer rely on md5 for anything in notary.

We'll necessarily have to keep legacy reading code for some time, but plan to remove any code that creates encrypted PEMs.

Contributor

endophage commented Mar 31, 2017

Something I should bring to everyone's attention as a consideration before merging this PR. We're actually planning to deprecate the encrypted PEMs in notary in place of PKCS#8 in the very near future (next 6-8 weeks). We didn't realize at the time but encrypted PEMs use md5 for deriving keys from passwords and we want to ultimately no longer rely on md5 for anything in notary.

We'll necessarily have to keep legacy reading code for some time, but plan to remove any code that creates encrypted PEMs.

@adshmh

This comment has been minimized.

Show comment
Hide comment
@adshmh

adshmh Apr 5, 2017

Contributor

@vdemeester Thank you for merging the go-connections PR. I have updated the PR and added a commit to vendor go-connections.

Contributor

adshmh commented Apr 5, 2017

@vdemeester Thank you for merging the go-connections PR. I have updated the PR and added a commit to vendor go-connections.

Show outdated Hide outdated cli/command/cli.go Outdated
Show outdated Hide outdated cli/command/cli.go Outdated
passwd string
giveup bool
)
passRetriever := passphrase.PromptRetrieverWithInOut(cli.In(), cli.Out(), nil)

This comment has been minimized.

@cpuguy83

cpuguy83 Apr 6, 2017

Contributor

Check for encrypted key error before getting a new pass retriever

@cpuguy83

cpuguy83 Apr 6, 2017

Contributor

Check for encrypted key error before getting a new pass retriever

This comment has been minimized.

@adshmh

adshmh Apr 6, 2017

Contributor

Would it be OK if I put all the block under that condition? It results in one extra call to IsErrEncryptedKey, but perhaps it is more readable?

      if tlsconfig.IsErrEncryptedKey(err) {
                var (
                        passwd string
                        giveup bool
                )
                passRetriever := passphrase.PromptRetrieverWithInOut(cli.In(), cli.Out(), nil)

                for attempts := 0; tlsconfig.IsErrEncryptedKey(err); attempts++ {
                        // some code and comments borrowed from notary/trustmanager/keystore.go
                        passwd, giveup, err = passRetriever("private", "encrypted TLS private", false, attempts)
                        // Check if the passphrase retriever got an error or if it is telling us to give up
                        if giveup || err != nil {
                                return errors.Wrap(err, "private key is encrypted, but could not get passphrase")
                        }

                        opts.Common.TLSOptions.Passphrase = passwd
                        cli.client, err = NewAPIClientFromFlags(opts.Common, cli.configFile)
                }
        }

        if err != nil {
                return err
        }

@adshmh

adshmh Apr 6, 2017

Contributor

Would it be OK if I put all the block under that condition? It results in one extra call to IsErrEncryptedKey, but perhaps it is more readable?

      if tlsconfig.IsErrEncryptedKey(err) {
                var (
                        passwd string
                        giveup bool
                )
                passRetriever := passphrase.PromptRetrieverWithInOut(cli.In(), cli.Out(), nil)

                for attempts := 0; tlsconfig.IsErrEncryptedKey(err); attempts++ {
                        // some code and comments borrowed from notary/trustmanager/keystore.go
                        passwd, giveup, err = passRetriever("private", "encrypted TLS private", false, attempts)
                        // Check if the passphrase retriever got an error or if it is telling us to give up
                        if giveup || err != nil {
                                return errors.Wrap(err, "private key is encrypted, but could not get passphrase")
                        }

                        opts.Common.TLSOptions.Passphrase = passwd
                        cli.client, err = NewAPIClientFromFlags(opts.Common, cli.configFile)
                }
        }

        if err != nil {
                return err
        }

This comment has been minimized.

@cpuguy83

cpuguy83 Apr 7, 2017

Contributor

SGTM

@cpuguy83

cpuguy83 Apr 7, 2017

Contributor

SGTM

adshmh added some commits Apr 5, 2017

vendor docker/go-connections to include the enhacement for decrypting…
… keys

Signed-off-by: Arash Deshmeh <adeshmeh@ca.ibm.com>
use an encrypted client certificate to connect to a docker daemon
Signed-off-by: Arash Deshmeh <adeshmeh@ca.ibm.com>
@adshmh

This comment has been minimized.

Show comment
Hide comment
@adshmh

adshmh Apr 7, 2017

Contributor

@cpuguy83 Thank you for the review. I have updated the PR with the requested changes.

Contributor

adshmh commented Apr 7, 2017

@cpuguy83 Thank you for the review. I have updated the PR with the requested changes.

@cpuguy83

LGTM

@vdemeester

LGTM 🐯
/cc @n4ss @diogomonica 👼

@diogomonica

This comment has been minimized.

Show comment
Hide comment
@diogomonica

diogomonica Apr 7, 2017

Contributor

No picture of a cute animal 👎

Contributor

diogomonica commented Apr 7, 2017

No picture of a cute animal 👎

@thaJeztah

This comment has been minimized.

Show comment
Hide comment
@thaJeztah

thaJeztah Apr 10, 2017

Member

@diogomonica best I could find, good to go?

monkey-tomato

Member

thaJeztah commented Apr 10, 2017

@diogomonica best I could find, good to go?

monkey-tomato

@thaJeztah

LGTM

@thaJeztah thaJeztah merged commit 2daa2b8 into moby:master Apr 10, 2017

7 checks passed

dco-signed All commits are signed
experimental Jenkins build Docker-PRs-experimental 32668 has succeeded
Details
janky Jenkins build Docker-PRs 41278 has succeeded
Details
powerpc Jenkins build Docker-PRs-powerpc 1459 has succeeded
Details
vendor Jenkins build Docker-PRs-vendor 3134 has succeeded
Details
windowsRS1 Jenkins build Docker-PRs-WoW-RS1 12395 has succeeded
Details
z Jenkins build Docker-PRs-s390x 1292 has succeeded
Details

@GordonTheTurtle GordonTheTurtle added this to the 17.05.0 milestone Apr 10, 2017

dnephin pushed a commit to dnephin/docker that referenced this pull request Apr 17, 2017

Merge pull request moby#31364 from adshmh/30935-use-encrypted-client-…
…certificate-to-connect-to-a-docker-host

use an encrypted client certificate to connect to a docker daemon
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment