From 6fa95eb497ba2b3e1aa53c9cecd437251a7bedee 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 | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ embed/etcd.go | 33 ++++++++----------------- 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/embed/config.go b/embed/config.go index 794c2aee3..d414789ba 100644 --- a/embed/config.go +++ b/embed/config.go @@ -20,6 +20,7 @@ import ( "net" "net/http" "net/url" + "path/filepath" "strings" "time" @@ -27,6 +28,7 @@ import ( "github.com/coreos/etcd/pkg/cors" "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" @@ -158,6 +160,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"` + // debug Debug bool `json:"debug"` @@ -329,6 +336,25 @@ 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 := checkBindURLs(cfg.LPUrls); err != nil { return err @@ -431,6 +457,44 @@ func (cfg Config) defaultClientHost() bool { return len(cfg.ACUrls) == 1 && cfg.ACUrls[0].String() == DefaultAdvertiseClientURLs } +func (cfg *Config) ClientSelfCert() (err error) { + if !cfg.ClientAutoTLS { + return nil + } + if !cfg.ClientTLSInfo.Empty() { + plog.Warningf("ignoring client auto TLS since certs given") + return nil + } + chosts := make([]string, len(cfg.LCUrls)) + for i, u := range cfg.LCUrls { + chosts[i] = u.Host + } + cfg.ClientTLSInfo, err = transport.SelfCert(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 { + return nil + } + if !cfg.PeerTLSInfo.Empty() { + plog.Warningf("ignoring peer auto TLS since certs given") + return nil + } + phosts := make([]string, len(cfg.LPUrls)) + for i, u := range cfg.LPUrls { + phosts[i] = u.Host + } + cfg.PeerTLSInfo, err = transport.SelfCert(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, // if advertise URLs are default values(localhost:2379,2380) AND if listen URL is 0.0.0.0. // e.g. advertise peer URL localhost:2380 or listen peer URL 0.0.0.0:2380 diff --git a/embed/etcd.go b/embed/etcd.go index 874779dc1..9ae55c134 100644 --- a/embed/etcd.go +++ b/embed/etcd.go @@ -22,7 +22,6 @@ import ( defaultLog "log" "net" "net/http" - "path/filepath" "sync" "time" @@ -264,17 +263,11 @@ func stopServers(ctx context.Context, ss *servers) { func (e *Etcd) Err() <-chan error { return e.errc } func startPeerListeners(cfg *Config) (peers []*peerListener, 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(filepath.Join(cfg.Dir, "fixtures", "peer"), phosts) - if err != nil { - plog.Fatalf("could not get certs (%v)", err) - } - } else if cfg.PeerAutoTLS { - plog.Warningf("ignoring peer auto TLS since certs given") + if err = updateCipherSuites(&cfg.PeerTLSInfo, cfg.CipherSuites); err != nil { + return nil, err + } + if err = cfg.PeerSelfCert(); err != nil { + plog.Fatalf("could not get certs (%v)", err) } if !cfg.PeerTLSInfo.Empty() { @@ -359,17 +352,11 @@ func (e *Etcd) servePeers() (err error) { } func startClientListeners(cfg *Config) (sctxs map[string]*serveCtx, 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(filepath.Join(cfg.Dir, "fixtures", "client"), chosts) - if err != nil { - plog.Fatalf("could not get certs (%v)", err) - } - } else if cfg.ClientAutoTLS { - plog.Warningf("ignoring client auto TLS since certs given") + if err = updateCipherSuites(&cfg.ClientTLSInfo, cfg.CipherSuites); err != nil { + return nil, err + } + if err = cfg.ClientSelfCert(); err != nil { + plog.Fatalf("could not get certs (%v)", err) } if cfg.EnablePprof {