mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
Add TLSv1.3 support.
Added optional TLS min/max protocol version and command line switches to set versions for the etcd server. If max version is not explicitly set by the user, let Go select the max version which is currently TLSv1.3. Previously max version was set to TLSv1.2. Signed-off-by: Tero Saarni <tero.saarni@est.tech>
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
package embed
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -226,6 +227,11 @@ type Config struct {
|
||||
// Note that cipher suites are prioritized in the given order.
|
||||
CipherSuites []string `json:"cipher-suites"`
|
||||
|
||||
// TlsMinVersion is the minimum accepted TLS version between client/server and peers.
|
||||
TlsMinVersion string `json:"tls-min-version"`
|
||||
// TlsMaxVersion is the maximum accepted TLS version between client/server and peers.
|
||||
TlsMaxVersion string `json:"tls-max-version"`
|
||||
|
||||
ClusterState string `json:"initial-cluster-state"`
|
||||
DNSCluster string `json:"discovery-srv"`
|
||||
DNSClusterServiceName string `json:"discovery-srv-name"`
|
||||
@@ -660,6 +666,17 @@ func updateCipherSuites(tls *transport.TLSInfo, ss []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateMinMaxVersions(info *transport.TLSInfo, min, max string) {
|
||||
// Validate() has been called to check the user input, so it should never fail.
|
||||
var err error
|
||||
if info.MinVersion, err = tlsutil.GetTLSVersion(min); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if info.MaxVersion, err = tlsutil.GetTLSVersion(max); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate ensures that '*embed.Config' fields are properly configured.
|
||||
func (cfg *Config) Validate() error {
|
||||
if err := cfg.setupLogging(); err != nil {
|
||||
@@ -776,6 +793,25 @@ func (cfg *Config) Validate() error {
|
||||
zap.String("name", cfg.Name))
|
||||
}
|
||||
|
||||
minVersion, err := tlsutil.GetTLSVersion(cfg.TlsMinVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
maxVersion, err := tlsutil.GetTLSVersion(cfg.TlsMaxVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// maxVersion == 0 means that Go selects the highest available version.
|
||||
if maxVersion != 0 && minVersion > maxVersion {
|
||||
return fmt.Errorf("min version (%s) is greater than max version (%s)", cfg.TlsMinVersion, cfg.TlsMaxVersion)
|
||||
}
|
||||
|
||||
// Check if user attempted to configure ciphers for TLS1.3 only: Go does not support that currently.
|
||||
if minVersion == tls.VersionTLS13 && len(cfg.CipherSuites) > 0 {
|
||||
return fmt.Errorf("cipher suites cannot be configured when only TLS1.3 is enabled")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package embed
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
@@ -429,3 +430,80 @@ func TestLogRotation(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSVersionMinMax(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
givenTLSMinVersion string
|
||||
givenTLSMaxVersion string
|
||||
givenCipherSuites []string
|
||||
expectError bool
|
||||
expectedMinTLSVersion uint16
|
||||
expectedMaxTLSVersion uint16
|
||||
}{
|
||||
{
|
||||
name: "Minimum TLS version is set",
|
||||
givenTLSMinVersion: "TLS1.3",
|
||||
expectedMinTLSVersion: tls.VersionTLS13,
|
||||
expectedMaxTLSVersion: 0,
|
||||
},
|
||||
{
|
||||
name: "Maximum TLS version is set",
|
||||
givenTLSMaxVersion: "TLS1.2",
|
||||
expectedMinTLSVersion: 0,
|
||||
expectedMaxTLSVersion: tls.VersionTLS12,
|
||||
},
|
||||
{
|
||||
name: "Minimum and Maximum TLS versions are set",
|
||||
givenTLSMinVersion: "TLS1.3",
|
||||
givenTLSMaxVersion: "TLS1.3",
|
||||
expectedMinTLSVersion: tls.VersionTLS13,
|
||||
expectedMaxTLSVersion: tls.VersionTLS13,
|
||||
},
|
||||
{
|
||||
name: "Minimum and Maximum TLS versions are set in reverse order",
|
||||
givenTLSMinVersion: "TLS1.3",
|
||||
givenTLSMaxVersion: "TLS1.2",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "Invalid minimum TLS version",
|
||||
givenTLSMinVersion: "invalid version",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "Invalid maximum TLS version",
|
||||
givenTLSMaxVersion: "invalid version",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "Cipher suites configured for TLS 1.3",
|
||||
givenTLSMinVersion: "TLS1.3",
|
||||
givenCipherSuites: []string{"TLS_AES_128_GCM_SHA256"},
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := NewConfig()
|
||||
cfg.TlsMinVersion = tt.givenTLSMinVersion
|
||||
cfg.TlsMaxVersion = tt.givenTLSMaxVersion
|
||||
cfg.CipherSuites = tt.givenCipherSuites
|
||||
|
||||
err := cfg.Validate()
|
||||
if err != nil {
|
||||
assert.True(t, tt.expectError, "Validate() returned error while expecting success: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
updateMinMaxVersions(&cfg.PeerTLSInfo, cfg.TlsMinVersion, cfg.TlsMaxVersion)
|
||||
updateMinMaxVersions(&cfg.ClientTLSInfo, cfg.TlsMinVersion, cfg.TlsMaxVersion)
|
||||
|
||||
assert.Equal(t, tt.expectedMinTLSVersion, cfg.PeerTLSInfo.MinVersion)
|
||||
assert.Equal(t, tt.expectedMaxTLSVersion, cfg.PeerTLSInfo.MaxVersion)
|
||||
assert.Equal(t, tt.expectedMinTLSVersion, cfg.ClientTLSInfo.MinVersion)
|
||||
assert.Equal(t, tt.expectedMaxTLSVersion, cfg.ClientTLSInfo.MaxVersion)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,6 +499,7 @@ func configurePeerListeners(cfg *Config) (peers []*peerListener, err error) {
|
||||
if err = cfg.PeerSelfCert(); err != nil {
|
||||
cfg.logger.Fatal("failed to get peer self-signed certs", zap.Error(err))
|
||||
}
|
||||
updateMinMaxVersions(&cfg.PeerTLSInfo, cfg.TlsMinVersion, cfg.TlsMaxVersion)
|
||||
if !cfg.PeerTLSInfo.Empty() {
|
||||
cfg.logger.Info(
|
||||
"starting with peer TLS",
|
||||
@@ -611,6 +612,7 @@ func configureClientListeners(cfg *Config) (sctxs map[string]*serveCtx, err erro
|
||||
if err = cfg.ClientSelfCert(); err != nil {
|
||||
cfg.logger.Fatal("failed to get client self-signed certs", zap.Error(err))
|
||||
}
|
||||
updateMinMaxVersions(&cfg.ClientTLSInfo, cfg.TlsMinVersion, cfg.TlsMaxVersion)
|
||||
if cfg.EnablePprof {
|
||||
cfg.logger.Info("pprof is enabled", zap.String("path", debugutil.HTTPPrefixPProf))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user