Merge pull request #3220 from thaJeztah/remove_encrypted_tls_support

Remove support for encrypted TLS private keys
This commit is contained in:
Justin Cormack 2022-01-27 18:05:32 +00:00 committed by GitHub
commit 2b0e74c207
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 14 additions and 107 deletions

View File

@ -33,9 +33,7 @@ import (
"github.com/moby/term" "github.com/moby/term"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/theupdateframework/notary"
notaryclient "github.com/theupdateframework/notary/client" notaryclient "github.com/theupdateframework/notary/client"
"github.com/theupdateframework/notary/passphrase"
) )
// Streams is an interface which exposes the standard input and output streams // Streams is an interface which exposes the standard input and output streams
@ -252,14 +250,6 @@ func (cli *DockerCli) Initialize(opts *cliflags.ClientOptions, ops ...Initialize
if cli.client == nil { if cli.client == nil {
cli.client, err = newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile) cli.client, err = newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile)
if tlsconfig.IsErrEncryptedKey(err) {
passRetriever := passphrase.PromptRetrieverWithInOut(cli.In(), cli.Out(), nil)
newClient := func(password string) (client.APIClient, error) {
cli.dockerEndpoint.TLSPassword = password //nolint: staticcheck // SA1019: cli.dockerEndpoint.TLSPassword is deprecated
return newAPIClientFromEndpoint(cli.dockerEndpoint, cli.configFile)
}
cli.client, err = getClientWithPassword(passRetriever, newClient)
}
if err != nil { if err != nil {
return err return err
} }
@ -377,20 +367,6 @@ func (cli *DockerCli) initializeFromClient() {
cli.client.NegotiateAPIVersionPing(ping) cli.client.NegotiateAPIVersionPing(ping)
} }
func getClientWithPassword(passRetriever notary.PassRetriever, newClient func(password string) (client.APIClient, error)) (client.APIClient, error) {
for attempts := 0; ; attempts++ {
passwd, giveup, err := passRetriever("private", "encrypted TLS private", false, attempts)
if giveup || err != nil {
return nil, errors.Wrap(err, "private key is encrypted, but could not get passphrase")
}
apiclient, err := newClient(passwd)
if !tlsconfig.IsErrEncryptedKey(err) {
return apiclient, err
}
}
}
// NotaryClient provides a Notary Repository to interact with signed metadata for an image // NotaryClient provides a Notary Repository to interact with signed metadata for an image
func (cli *DockerCli) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) { func (cli *DockerCli) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) {
return trust.GetNotaryRepository(cli.In(), cli.Out(), UserAgent(), imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig(), actions...) return trust.GetNotaryRepository(cli.In(), cli.Out(), UserAgent(), imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig(), actions...)

View File

@ -3,7 +3,6 @@ package command
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/x509"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@ -209,73 +208,6 @@ func TestExperimentalCLI(t *testing.T) {
} }
} }
func TestGetClientWithPassword(t *testing.T) {
expected := "password"
var testcases = []struct {
doc string
password string
retrieverErr error
retrieverGiveup bool
newClientErr error
expectedErr string
}{
{
doc: "successful connect",
password: expected,
},
{
doc: "password retriever exhausted",
retrieverGiveup: true,
retrieverErr: errors.New("failed"),
expectedErr: "private key is encrypted, but could not get passphrase",
},
{
doc: "password retriever error",
retrieverErr: errors.New("failed"),
expectedErr: "failed",
},
{
doc: "newClient error",
newClientErr: errors.New("failed to connect"),
expectedErr: "failed to connect",
},
}
for _, testcase := range testcases {
testcase := testcase
t.Run(testcase.doc, func(t *testing.T) {
passRetriever := func(_, _ string, _ bool, attempts int) (passphrase string, giveup bool, err error) {
// Always return an invalid pass first to test iteration
switch attempts {
case 0:
return "something else", false, nil
default:
return testcase.password, testcase.retrieverGiveup, testcase.retrieverErr
}
}
newClient := func(currentPassword string) (client.APIClient, error) {
if testcase.newClientErr != nil {
return nil, testcase.newClientErr
}
if currentPassword == expected {
return &client.Client{}, nil
}
return &client.Client{}, x509.IncorrectPasswordError
}
_, err := getClientWithPassword(passRetriever, newClient)
if testcase.expectedErr != "" {
assert.ErrorContains(t, err, testcase.expectedErr)
return
}
assert.NilError(t, err)
})
}
}
func TestNewDockerCliAndOperators(t *testing.T) { func TestNewDockerCliAndOperators(t *testing.T) {
// Test default operations and also overriding default ones // Test default operations and also overriding default ones
cli, err := NewDockerCli( cli, err := NewDockerCli(

View File

@ -4,7 +4,6 @@ import (
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/pem" "encoding/pem"
"fmt"
"net" "net"
"net/http" "net/http"
"os" "os"
@ -67,17 +66,10 @@ func (c *Endpoint) tlsConfig() (*tls.Config, error) {
keyBytes := c.TLSData.Key keyBytes := c.TLSData.Key
pemBlock, _ := pem.Decode(keyBytes) pemBlock, _ := pem.Decode(keyBytes)
if pemBlock == nil { if pemBlock == nil {
return nil, fmt.Errorf("no valid private key found") return nil, errors.New("no valid private key found")
} }
var err error
// TODO should we follow Golang, and deprecate RFC 1423 encryption, and produce a warning (or just error)? see https://github.com/docker/cli/issues/3212
if x509.IsEncryptedPEMBlock(pemBlock) { //nolint: staticcheck // SA1019: x509.IsEncryptedPEMBlock is deprecated, and insecure by design if x509.IsEncryptedPEMBlock(pemBlock) { //nolint: staticcheck // SA1019: x509.IsEncryptedPEMBlock is deprecated, and insecure by design
keyBytes, err = x509.DecryptPEMBlock(pemBlock, []byte(c.TLSPassword)) //nolint: staticcheck // SA1019: x509.IsEncryptedPEMBlock is deprecated, and insecure by design return nil, errors.New("private key is encrypted - support for encrypted private keys has been removed, see https://docs.docker.com/go/deprecated/")
if err != nil {
return nil, errors.Wrap(err, "private key is encrypted, but could not decrypt it")
}
keyBytes = pem.EncodeToMemory(&pem.Block{Type: pemBlock.Type, Bytes: keyBytes})
} }
x509cert, err := tls.X509KeyPair(c.TLSData.Cert, keyBytes) x509cert, err := tls.X509KeyPair(c.TLSData.Cert, keyBytes)

View File

@ -50,7 +50,7 @@ The table below provides an overview of the current status of deprecated feature
Status | Feature | Deprecated | Remove Status | Feature | Deprecated | Remove
-----------|------------------------------------------------------------------------------------------------------------------------------------|------------|------------ -----------|------------------------------------------------------------------------------------------------------------------------------------|------------|------------
Deprecated | [Support for encrypted TLS private keys](#support-for-encrypted-tls-private-keys) | v20.10 | - Removed | [Support for encrypted TLS private keys](#support-for-encrypted-tls-private-keys) | v20.10 | v21.xx
Deprecated | [Kubernetes stack and context support](#kubernetes-stack-and-context-support) | v20.10 | - Deprecated | [Kubernetes stack and context support](#kubernetes-stack-and-context-support) | v20.10 | -
Deprecated | [Pulling images from non-compliant image registries](#pulling-images-from-non-compliant-image-registries) | v20.10 | - Deprecated | [Pulling images from non-compliant image registries](#pulling-images-from-non-compliant-image-registries) | v20.10 | -
Removed | [Linux containers on Windows (LCOW)](#linux-containers-on-windows-lcow-experimental) | v20.10 | v21.xx Removed | [Linux containers on Windows (LCOW)](#linux-containers-on-windows-lcow-experimental) | v20.10 | v21.xx
@ -103,10 +103,17 @@ Removed | [Three arguments form in `docker import`](#three-arguments-form-in-
**Deprecated in Release: v20.10** **Deprecated in Release: v20.10**
Use of encrypted TLS private keys has been deprecated, and will be removed in a **Removed in Release: v21.xx**
future release. Golang has deprecated support for legacy PEM encryption (as
specified in [RFC 1423](https://datatracker.ietf.org/doc/html/rfc1423)), as it Use of encrypted TLS private keys has been deprecated, and has been removed.
is insecure by design (see [https://go-review.googlesource.com/c/go/+/264159](https://go-review.googlesource.com/c/go/+/264159)). Golang has deprecated support for legacy PEM encryption (as specified in
[RFC 1423](https://datatracker.ietf.org/doc/html/rfc1423)), as it is insecure by
design (see [https://go-review.googlesource.com/c/go/+/264159](https://go-review.googlesource.com/c/go/+/264159)).
This feature allowed using an encrypted private key with a supplied password,
but did not provide additional security as the encryption is known to be broken,
and the key is sitting next to the password in the filesystem. Users are recommended
to decrypt the private key, and store it un-encrypted to continue using it.
### Kubernetes stack and context support ### Kubernetes stack and context support