From 3125c0c3e81f4e43b931777a8818b3a476170c1d Mon Sep 17 00:00:00 2001 From: Gyuho Lee Date: Mon, 4 Jun 2018 08:45:16 -0700 Subject: [PATCH] embed: support custom cipher suites Signed-off-by: Gyuho Lee --- embed/config.go | 70 ++++++++++++++++++++++++++++++++++++------------- embed/etcd.go | 13 ++++++++- 2 files changed, 64 insertions(+), 19 deletions(-) diff --git a/embed/config.go b/embed/config.go index 850b0c9b0..0fccc74bf 100644 --- a/embed/config.go +++ b/embed/config.go @@ -32,6 +32,7 @@ import ( "github.com/coreos/etcd/pkg/flags" "github.com/coreos/etcd/pkg/netutil" "github.com/coreos/etcd/pkg/srv" + "github.com/coreos/etcd/pkg/tlsutil" "github.com/coreos/etcd/pkg/transport" "github.com/coreos/etcd/pkg/types" @@ -175,6 +176,11 @@ type Config struct { PeerTLSInfo transport.TLSInfo PeerAutoTLS bool + // CipherSuites is a list of supported TLS cipher suites between + // client/server and peers. If empty, Go auto-populates the list. + // Note that cipher suites are prioritized in the given order. + CipherSuites []string `json:"cipher-suites"` + ClusterState string `json:"initial-cluster-state"` DNSCluster string `json:"discovery-srv"` DNSClusterServiceName string `json:"discovery-srv-name"` @@ -510,6 +516,24 @@ func (cfg *configYAML) configFromFile(path string) error { return cfg.Validate() } +func updateCipherSuites(tls *transport.TLSInfo, ss []string) error { + if len(tls.CipherSuites) > 0 && len(ss) > 0 { + return fmt.Errorf("TLSInfo.CipherSuites is already specified (given %v)", ss) + } + if len(ss) > 0 { + cs := make([]uint16, len(ss)) + for i, s := range ss { + var ok bool + cs[i], ok = tlsutil.GetCipherSuite(s) + if !ok { + return fmt.Errorf("unexpected TLS cipher suite %q", s) + } + } + tls.CipherSuites = cs + } + return nil +} + // Validate ensures that '*embed.Config' fields are properly configured. func (cfg *Config) Validate() error { if err := cfg.setupLogging(); err != nil { @@ -703,39 +727,49 @@ func (cfg Config) defaultClientHost() bool { } func (cfg *Config) ClientSelfCert() (err error) { - if cfg.ClientAutoTLS && cfg.ClientTLSInfo.Empty() { - chosts := make([]string, len(cfg.LCUrls)) - for i, u := range cfg.LCUrls { - chosts[i] = u.Host - } - cfg.ClientTLSInfo, err = transport.SelfCert(cfg.logger, filepath.Join(cfg.Dir, "fixtures", "client"), chosts) - return err - } else if cfg.ClientAutoTLS { + if !cfg.ClientAutoTLS { + return nil + } + if !cfg.ClientTLSInfo.Empty() { if cfg.logger != nil { cfg.logger.Warn("ignoring client auto TLS since certs given") } else { plog.Warningf("ignoring client auto TLS since certs given") } + return nil } - return nil + chosts := make([]string, len(cfg.LCUrls)) + for i, u := range cfg.LCUrls { + chosts[i] = u.Host + } + cfg.ClientTLSInfo, err = transport.SelfCert(cfg.logger, filepath.Join(cfg.Dir, "fixtures", "client"), chosts) + if err != nil { + return err + } + return updateCipherSuites(&cfg.ClientTLSInfo, cfg.CipherSuites) } func (cfg *Config) PeerSelfCert() (err error) { - if cfg.PeerAutoTLS && cfg.PeerTLSInfo.Empty() { - phosts := make([]string, len(cfg.LPUrls)) - for i, u := range cfg.LPUrls { - phosts[i] = u.Host - } - cfg.PeerTLSInfo, err = transport.SelfCert(cfg.logger, filepath.Join(cfg.Dir, "fixtures", "peer"), phosts) - return err - } else if cfg.PeerAutoTLS { + if !cfg.PeerAutoTLS { + return nil + } + if !cfg.PeerTLSInfo.Empty() { if cfg.logger != nil { cfg.logger.Warn("ignoring peer auto TLS since certs given") } else { plog.Warningf("ignoring peer auto TLS since certs given") } + return nil } - return nil + phosts := make([]string, len(cfg.LPUrls)) + for i, u := range cfg.LPUrls { + phosts[i] = u.Host + } + cfg.PeerTLSInfo, err = transport.SelfCert(cfg.logger, filepath.Join(cfg.Dir, "fixtures", "peer"), phosts) + if err != nil { + return err + } + return updateCipherSuites(&cfg.PeerTLSInfo, cfg.CipherSuites) } // UpdateDefaultClusterFromName updates cluster advertise URLs with, if available, default host, diff --git a/embed/etcd.go b/embed/etcd.go index d10224331..f83eb8e23 100644 --- a/embed/etcd.go +++ b/embed/etcd.go @@ -375,6 +375,9 @@ func stopServers(ctx context.Context, ss *servers) { func (e *Etcd) Err() <-chan error { return e.errc } func configurePeerListeners(cfg *Config) (peers []*peerListener, err error) { + if err = updateCipherSuites(&cfg.PeerTLSInfo, cfg.CipherSuites); err != nil { + return nil, err + } if err = cfg.PeerSelfCert(); err != nil { if cfg.logger != nil { cfg.logger.Fatal("failed to get peer self-signed certs", zap.Error(err)) @@ -384,7 +387,11 @@ func configurePeerListeners(cfg *Config) (peers []*peerListener, err error) { } if !cfg.PeerTLSInfo.Empty() { if cfg.logger != nil { - cfg.logger.Info("starting with peer TLS", zap.String("tls-info", fmt.Sprintf("%+v", cfg.PeerTLSInfo))) + cfg.logger.Info( + "starting with peer TLS", + zap.String("tls-info", fmt.Sprintf("%+v", cfg.PeerTLSInfo)), + zap.Strings("cipher-suites", cfg.CipherSuites), + ) } else { plog.Infof("peerTLS: %s", cfg.PeerTLSInfo) } @@ -505,6 +512,9 @@ func (e *Etcd) servePeers() (err error) { } func configureClientListeners(cfg *Config) (sctxs map[string]*serveCtx, err error) { + if err = updateCipherSuites(&cfg.ClientTLSInfo, cfg.CipherSuites); err != nil { + return nil, err + } if err = cfg.ClientSelfCert(); err != nil { if cfg.logger != nil { cfg.logger.Fatal("failed to get client self-signed certs", zap.Error(err)) @@ -623,6 +633,7 @@ func (e *Etcd) serveClients() (err error) { e.cfg.logger.Info( "starting with client TLS", zap.String("tls-info", fmt.Sprintf("%+v", e.cfg.ClientTLSInfo)), + zap.Strings("cipher-suites", e.cfg.CipherSuites), ) } else { plog.Infof("ClientTLS: %s", e.cfg.ClientTLSInfo)