Refactor TLS code with a new tlsconfig package
This patch creates a new `tlsconfig` package to handle creation of secure-enough TLS configurations for clients and servers. The package was created by refactoring TLS code in the client and the daemon. After this patch, it is expected that all code creating TLS configurations use this `tlsconfig` package for greater security, consistency and readability. On the server side, this fixes a bug where --tlsverify was not taken into account. Now, if specified, it will require the client to authenticate. Signed-off-by: Tibor Vass <tibor@docker.com> Upstream-commit: bfed4b7cc3820ee3a74580aca55d5918bf05eef5 Component: engine
This commit is contained in:
@ -3,6 +3,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@ -21,6 +22,7 @@ import (
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/pkg/timeutils"
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/utils"
|
||||
)
|
||||
@ -112,11 +114,17 @@ func mainDaemon() {
|
||||
CorsHeaders: daemonCfg.CorsHeaders,
|
||||
Version: dockerversion.VERSION,
|
||||
SocketGroup: daemonCfg.SocketGroup,
|
||||
Tls: *flTls,
|
||||
TlsVerify: *flTlsVerify,
|
||||
TlsCa: *flCa,
|
||||
TlsCert: *flCert,
|
||||
TlsKey: *flKey,
|
||||
}
|
||||
|
||||
if *flTls {
|
||||
if *flTlsVerify {
|
||||
tlsOptions.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
tlsConfig, err := tlsconfig.Server(tlsOptions)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
serverConfig.TLSConfig = tlsConfig
|
||||
}
|
||||
|
||||
api := apiserver.New(serverConfig)
|
||||
|
||||
@ -2,9 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
@ -16,6 +14,7 @@ import (
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
"github.com/docker/docker/pkg/term"
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
"github.com/docker/docker/utils"
|
||||
)
|
||||
|
||||
@ -85,6 +84,12 @@ func main() {
|
||||
|
||||
setDefaultConfFlag(flTrustKey, defaultTrustKeyFile)
|
||||
|
||||
// Regardless of whether the user sets it to true or false, if they
|
||||
// specify --tlsverify at all then we need to turn on tls
|
||||
if flag.IsSet("-tlsverify") {
|
||||
*flTls = true
|
||||
}
|
||||
|
||||
if *flDaemon {
|
||||
if *flHelp {
|
||||
flag.Usage()
|
||||
@ -94,59 +99,35 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
// From here on, we assume we're a client, not a server.
|
||||
|
||||
if len(flHosts) > 1 {
|
||||
fmt.Fprintf(os.Stderr, "Please specify only one -H")
|
||||
os.Exit(0)
|
||||
}
|
||||
protoAddrParts := strings.SplitN(flHosts[0], "://", 2)
|
||||
|
||||
var (
|
||||
cli *client.DockerCli
|
||||
tlsConfig tls.Config
|
||||
)
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
|
||||
// Regardless of whether the user sets it to true or false, if they
|
||||
// specify --tlsverify at all then we need to turn on tls
|
||||
if flag.IsSet("-tlsverify") {
|
||||
*flTls = true
|
||||
}
|
||||
|
||||
// If we should verify the server, we need to load a trusted ca
|
||||
if *flTlsVerify {
|
||||
certPool := x509.NewCertPool()
|
||||
file, err := ioutil.ReadFile(*flCa)
|
||||
var tlsConfig *tls.Config
|
||||
if *flTls {
|
||||
tlsOptions.InsecureSkipVerify = !*flTlsVerify
|
||||
if !flag.IsSet("-tlscert") {
|
||||
if _, err := os.Stat(tlsOptions.CertFile); os.IsNotExist(err) {
|
||||
tlsOptions.CertFile = ""
|
||||
}
|
||||
}
|
||||
if !flag.IsSet("-tlskey") {
|
||||
if _, err := os.Stat(tlsOptions.KeyFile); os.IsNotExist(err) {
|
||||
tlsOptions.KeyFile = ""
|
||||
}
|
||||
}
|
||||
var err error
|
||||
tlsConfig, err = tlsconfig.Client(tlsOptions)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Couldn't read ca cert %s: %s\n", *flCa, err)
|
||||
fmt.Fprintln(stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
certPool.AppendCertsFromPEM(file)
|
||||
tlsConfig.RootCAs = certPool
|
||||
tlsConfig.InsecureSkipVerify = false
|
||||
}
|
||||
|
||||
// If tls is enabled, try to load and send client certificates
|
||||
if *flTls || *flTlsVerify {
|
||||
_, errCert := os.Stat(*flCert)
|
||||
_, errKey := os.Stat(*flKey)
|
||||
if errCert == nil && errKey == nil {
|
||||
*flTls = true
|
||||
cert, err := tls.LoadX509KeyPair(*flCert, *flKey)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Couldn't load X509 key pair: %q. Make sure the key is encrypted\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
// Avoid fallback to SSL protocols < TLS1.0
|
||||
tlsConfig.MinVersion = tls.VersionTLS10
|
||||
}
|
||||
|
||||
if *flTls || *flTlsVerify {
|
||||
cli = client.NewDockerCli(stdin, stdout, stderr, *flTrustKey, protoAddrParts[0], protoAddrParts[1], &tlsConfig)
|
||||
} else {
|
||||
cli = client.NewDockerCli(stdin, stdout, stderr, *flTrustKey, protoAddrParts[0], protoAddrParts[1], nil)
|
||||
}
|
||||
cli := client.NewDockerCli(stdin, stdout, stderr, *flTrustKey, protoAddrParts[0], protoAddrParts[1], tlsConfig)
|
||||
|
||||
if err := cli.Cmd(flag.Args()...); err != nil {
|
||||
if sterr, ok := err.(client.StatusError); ok {
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/pkg/homedir"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
@ -94,10 +95,8 @@ var (
|
||||
flTlsVerify = flag.Bool([]string{"-tlsverify"}, dockerTlsVerify, "Use TLS and verify the remote")
|
||||
|
||||
// these are initialized in init() below since their default values depend on dockerCertPath which isn't fully initialized until init() runs
|
||||
tlsOptions tlsconfig.Options
|
||||
flTrustKey *string
|
||||
flCa *string
|
||||
flCert *string
|
||||
flKey *string
|
||||
flHosts []string
|
||||
)
|
||||
|
||||
@ -116,9 +115,9 @@ func init() {
|
||||
// TODO use flag flag.String([]string{"i", "-identity"}, "", "Path to libtrust key file")
|
||||
flTrustKey = &placeholderTrustKey
|
||||
|
||||
flCa = flag.String([]string{"-tlscacert"}, filepath.Join(dockerCertPath, defaultCaFile), "Trust certs signed only by this CA")
|
||||
flCert = flag.String([]string{"-tlscert"}, filepath.Join(dockerCertPath, defaultCertFile), "Path to TLS certificate file")
|
||||
flKey = flag.String([]string{"-tlskey"}, filepath.Join(dockerCertPath, defaultKeyFile), "Path to TLS key file")
|
||||
flag.StringVar(&tlsOptions.CAFile, []string{"-tlscacert"}, filepath.Join(dockerCertPath, defaultCaFile), "Trust certs signed only by this CA")
|
||||
flag.StringVar(&tlsOptions.CertFile, []string{"-tlscert"}, filepath.Join(dockerCertPath, defaultCertFile), "Path to TLS certificate file")
|
||||
flag.StringVar(&tlsOptions.KeyFile, []string{"-tlskey"}, filepath.Join(dockerCertPath, defaultKeyFile), "Path to TLS key file")
|
||||
opts.HostListVar(&flHosts, []string{"H", "-host"}, "Daemon socket(s) to connect to")
|
||||
|
||||
flag.Usage = func() {
|
||||
|
||||
Reference in New Issue
Block a user