Browse Source

Merge pull request #2502 from kelseyhightower/trusted-ca-and-client-auth

etcd: server SSL and client cert auth configuration is more explicit
Kelsey Hightower 10 years ago
parent
commit
9c74f98b97
3 changed files with 66 additions and 28 deletions
  1. 4 0
      etcdmain/config.go
  2. 8 0
      etcdmain/help.go
  3. 54 28
      pkg/transport/listener.go

+ 4 - 0
etcdmain/config.go

@@ -172,9 +172,13 @@ func NewConfig() *config {
 	fs.StringVar(&cfg.clientTLSInfo.CAFile, "ca-file", "", "Path to the client server TLS CA file.")
 	fs.StringVar(&cfg.clientTLSInfo.CAFile, "ca-file", "", "Path to the client server TLS CA file.")
 	fs.StringVar(&cfg.clientTLSInfo.CertFile, "cert-file", "", "Path to the client server TLS cert file.")
 	fs.StringVar(&cfg.clientTLSInfo.CertFile, "cert-file", "", "Path to the client server TLS cert file.")
 	fs.StringVar(&cfg.clientTLSInfo.KeyFile, "key-file", "", "Path to the client server TLS key file.")
 	fs.StringVar(&cfg.clientTLSInfo.KeyFile, "key-file", "", "Path to the client server TLS key file.")
+	fs.BoolVar(&cfg.clientTLSInfo.ClientCertAuth, "client-cert-auth", false, "Enable client cert authentication.")
+	fs.StringVar(&cfg.clientTLSInfo.TrustedCAFile, "trusted-ca-file", "", "Path to the client server TLS trusted CA key file.")
 	fs.StringVar(&cfg.peerTLSInfo.CAFile, "peer-ca-file", "", "Path to the peer server TLS CA file.")
 	fs.StringVar(&cfg.peerTLSInfo.CAFile, "peer-ca-file", "", "Path to the peer server TLS CA file.")
 	fs.StringVar(&cfg.peerTLSInfo.CertFile, "peer-cert-file", "", "Path to the peer server TLS cert file.")
 	fs.StringVar(&cfg.peerTLSInfo.CertFile, "peer-cert-file", "", "Path to the peer server TLS cert file.")
 	fs.StringVar(&cfg.peerTLSInfo.KeyFile, "peer-key-file", "", "Path to the peer server TLS key file.")
 	fs.StringVar(&cfg.peerTLSInfo.KeyFile, "peer-key-file", "", "Path to the peer server TLS key file.")
+	fs.BoolVar(&cfg.peerTLSInfo.ClientCertAuth, "peer-client-cert-auth", false, "Enable peer client cert authentication.")
+	fs.StringVar(&cfg.peerTLSInfo.TrustedCAFile, "peer-trusted-ca-file", "", "Path to the peer server TLS trusted CA file.")
 
 
 	// unsafe
 	// unsafe
 	fs.BoolVar(&cfg.forceNewCluster, "force-new-cluster", false, "Force to create a new one member cluster")
 	fs.BoolVar(&cfg.forceNewCluster, "force-new-cluster", false, "Force to create a new one member cluster")

+ 8 - 0
etcdmain/help.go

@@ -81,12 +81,20 @@ security flags:
 		path to the client server TLS cert file.
 		path to the client server TLS cert file.
 	--key-file ''
 	--key-file ''
 		path to the client server TLS key file.
 		path to the client server TLS key file.
+	--client-cert-auth 'false'
+		enable client cert authentication.
+	--trusted-ca-file ''
+		path to the client server TLS trusted CA key file.
 	--peer-ca-file ''
 	--peer-ca-file ''
 		path to the peer server TLS CA file.
 		path to the peer server TLS CA file.
 	--peer-cert-file ''
 	--peer-cert-file ''
 		path to the peer server TLS cert file.
 		path to the peer server TLS cert file.
 	--peer-key-file ''
 	--peer-key-file ''
 		path to the peer server TLS key file.
 		path to the peer server TLS key file.
+	--peer-client-cert-auth 'false'
+		enable peer client cert authentication.
+	--peer-trusted-ca-file ''
+		path to the peer server TLS trusted CA file.
 
 
 
 
 unsafe flags:
 unsafe flags:

+ 54 - 28
pkg/transport/listener.go

@@ -66,9 +66,11 @@ func NewTransport(info TLSInfo) (*http.Transport, error) {
 }
 }
 
 
 type TLSInfo struct {
 type TLSInfo struct {
-	CertFile string
-	KeyFile  string
-	CAFile   string
+	CertFile       string
+	KeyFile        string
+	CAFile         string
+	TrustedCAFile  string
+	ClientCertAuth bool
 
 
 	// parseFunc exists to simplify testing. Typically, parseFunc
 	// parseFunc exists to simplify testing. Typically, parseFunc
 	// should be left nil. In that case, tls.X509KeyPair will be used.
 	// should be left nil. In that case, tls.X509KeyPair will be used.
@@ -115,29 +117,47 @@ func (info TLSInfo) baseConfig() (*tls.Config, error) {
 	return cfg, nil
 	return cfg, nil
 }
 }
 
 
-// ServerConfig generates a tls.Config object for use by an HTTP server
+// cafiles returns a list of CA file paths.
+func (info TLSInfo) cafiles() []string {
+	cs := make([]string, 0)
+	if info.CAFile != "" {
+		cs = append(cs, info.CAFile)
+	}
+	if info.TrustedCAFile != "" {
+		cs = append(cs, info.TrustedCAFile)
+	}
+	return cs
+}
+
+// ServerConfig generates a tls.Config object for use by an HTTP server.
 func (info TLSInfo) ServerConfig() (*tls.Config, error) {
 func (info TLSInfo) ServerConfig() (*tls.Config, error) {
 	cfg, err := info.baseConfig()
 	cfg, err := info.baseConfig()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if info.CAFile != "" {
+	cfg.ClientAuth = tls.NoClientCert
+	if info.CAFile != "" || info.ClientCertAuth {
 		cfg.ClientAuth = tls.RequireAndVerifyClientCert
 		cfg.ClientAuth = tls.RequireAndVerifyClientCert
-		cp, err := newCertPool(info.CAFile)
+	}
+
+	CAFiles := info.cafiles()
+	if len(CAFiles) > 0 {
+		cp, err := newCertPool(CAFiles)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
 		cfg.ClientCAs = cp
 		cfg.ClientCAs = cp
-	} else {
-		cfg.ClientAuth = tls.NoClientCert
 	}
 	}
 
 
 	return cfg, nil
 	return cfg, nil
 }
 }
 
 
-// ClientConfig generates a tls.Config object for use by an HTTP client
-func (info TLSInfo) ClientConfig() (cfg *tls.Config, err error) {
+// ClientConfig generates a tls.Config object for use by an HTTP client.
+func (info TLSInfo) ClientConfig() (*tls.Config, error) {
+	var cfg *tls.Config
+	var err error
+
 	if !info.Empty() {
 	if !info.Empty() {
 		cfg, err = info.baseConfig()
 		cfg, err = info.baseConfig()
 		if err != nil {
 		if err != nil {
@@ -147,34 +167,40 @@ func (info TLSInfo) ClientConfig() (cfg *tls.Config, err error) {
 		cfg = &tls.Config{}
 		cfg = &tls.Config{}
 	}
 	}
 
 
-	if info.CAFile != "" {
-		cfg.RootCAs, err = newCertPool(info.CAFile)
+	CAFiles := info.cafiles()
+	if len(CAFiles) > 0 {
+		cfg.RootCAs, err = newCertPool(CAFiles)
 		if err != nil {
 		if err != nil {
-			return
+			return nil, err
 		}
 		}
 	}
 	}
 
 
-	return
+	return cfg, nil
 }
 }
 
 
-// newCertPool creates x509 certPool with provided CA file
-func newCertPool(CAFile string) (*x509.CertPool, error) {
+// newCertPool creates x509 certPool with provided CA files.
+func newCertPool(CAFiles []string) (*x509.CertPool, error) {
 	certPool := x509.NewCertPool()
 	certPool := x509.NewCertPool()
-	pemByte, err := ioutil.ReadFile(CAFile)
-	if err != nil {
-		return nil, err
-	}
 
 
-	for {
-		var block *pem.Block
-		block, pemByte = pem.Decode(pemByte)
-		if block == nil {
-			return certPool, nil
-		}
-		cert, err := x509.ParseCertificate(block.Bytes)
+	for _, CAFile := range CAFiles {
+		pemByte, err := ioutil.ReadFile(CAFile)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		certPool.AddCert(cert)
+
+		for {
+			var block *pem.Block
+			block, pemByte = pem.Decode(pemByte)
+			if block == nil {
+				break
+			}
+			cert, err := x509.ParseCertificate(block.Bytes)
+			if err != nil {
+				return nil, err
+			}
+			certPool.AddCert(cert)
+		}
 	}
 	}
+
+	return certPool, nil
 }
 }