Merge pull request #2699 from hashicorp/f-tls-min-version

Add TLSMinVersion to config options
This commit is contained in:
Kyle Havlovitz 2017-02-01 16:31:53 -05:00 committed by GitHub
commit f48cd78bc5
8 changed files with 101 additions and 2 deletions

View file

@ -430,6 +430,7 @@ func (a *Agent) consulConfig() *consul.Config {
base.KeyFile = a.config.KeyFile
base.ServerName = a.config.ServerName
base.Domain = a.config.Domain
base.TLSMinVersion = a.config.TLSMinVersion
// Setup the ServerUp callback
base.ServerUp = a.state.ConsulServerUp

View file

@ -429,6 +429,9 @@ type Config struct {
// provide matches the certificate
ServerName string `mapstructure:"server_name"`
// TLSMinVersion is used to set the minimum TLS version used for TLS connections.
TLSMinVersion string `mapstructure:"tls_min_version"`
// StartJoin is a list of addresses to attempt to join when the
// agent starts. If Serf is unable to communicate with any of these
// addresses, then the agent will error and exit.
@ -771,6 +774,8 @@ func DefaultConfig() *Config {
ACLEnforceVersion8: Bool(false),
RetryInterval: 30 * time.Second,
RetryIntervalWan: 30 * time.Second,
TLSMinVersion: "tls10",
}
}
@ -1407,6 +1412,9 @@ func MergeConfig(a, b *Config) *Config {
if b.ServerName != "" {
result.ServerName = b.ServerName
}
if b.TLSMinVersion != "" {
result.TLSMinVersion = b.TLSMinVersion
}
if b.Checks != nil {
result.Checks = append(result.Checks, b.Checks...)
}

View file

@ -332,7 +332,7 @@ func TestDecodeConfig(t *testing.T) {
}
// TLS
input = `{"verify_incoming": true, "verify_outgoing": true, "verify_server_hostname": true}`
input = `{"verify_incoming": true, "verify_outgoing": true, "verify_server_hostname": true, "tls_min_version": "tls12"}`
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
if err != nil {
t.Fatalf("err: %s", err)
@ -350,6 +350,10 @@ func TestDecodeConfig(t *testing.T) {
t.Fatalf("bad: %#v", config)
}
if config.TLSMinVersion != "tls12" {
t.Fatalf("bad: %#v", config)
}
// TLS keys
input = `{"ca_file": "my/ca/file", "cert_file": "my.cert", "key_file": "key.pem", "server_name": "example.com"}`
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
@ -1621,6 +1625,7 @@ func TestMergeConfig(t *testing.T) {
CAFile: "test/ca.pem",
CertFile: "test/cert.pem",
KeyFile: "test/key.pem",
TLSMinVersion: "tls12",
Checks: []*CheckDefinition{nil},
Services: []*ServiceDefinition{nil},
StartJoin: []string{"1.1.1.1"},

View file

@ -62,7 +62,9 @@ func NewHTTPServers(agent *Agent, config *Config, logOutput io.Writer) ([]*HTTPS
CertFile: config.CertFile,
KeyFile: config.KeyFile,
NodeName: config.NodeName,
ServerName: config.ServerName}
ServerName: config.ServerName,
TLSMinVersion: config.TLSMinVersion,
}
tlsConfig, err := tlsConf.IncomingTLSConfig()
if err != nil {

View file

@ -144,6 +144,9 @@ type Config struct {
// provide matches the certificate
ServerName string
// TLSMinVersion is used to set the minimum TLS version used for TLS connections.
TLSMinVersion string
// RejoinAfterLeave controls our interaction with Serf.
// When set to false (default), a leave causes a Consul to not rejoin
// the cluster until an explicit join is received. If this is set to
@ -341,6 +344,8 @@ func DefaultConfig() *Config {
// bit longer to try to cover that period. This should be more
// than enough when running in the high performance mode.
RPCHoldTimeout: 7 * time.Second,
TLSMinVersion: "tls10",
}
// Increase our reap interval to 3 days instead of 24h.
@ -394,6 +399,7 @@ func (c *Config) tlsConfig() *tlsutil.Config {
NodeName: c.NodeName,
ServerName: c.ServerName,
Domain: c.Domain,
TLSMinVersion: c.TLSMinVersion,
}
return tlsConf
}

View file

@ -19,6 +19,13 @@ type DCWrapper func(dc string, conn net.Conn) (net.Conn, error)
// a constant value. This is usually done by currying DCWrapper.
type Wrapper func(conn net.Conn) (net.Conn, error)
// TLSLookup maps the tls_min_version configuration to the internal value
var TLSLookup = map[string]uint16{
"tls10": tls.VersionTLS10,
"tls11": tls.VersionTLS11,
"tls12": tls.VersionTLS12,
}
// Config used to create tls.Config
type Config struct {
// VerifyIncoming is used to verify the authenticity of incoming connections.
@ -61,6 +68,9 @@ type Config struct {
// Domain is the Consul TLD being used. Defaults to "consul."
Domain string
// TLSMinVersion is the minimum accepted TLS version that can be used.
TLSMinVersion string
}
// AppendCA opens and parses the CA file and adds the certificates to
@ -140,6 +150,15 @@ func (c *Config) OutgoingTLSConfig() (*tls.Config, error) {
tlsConfig.Certificates = []tls.Certificate{*cert}
}
// Check if a minimum TLS version was set
if c.TLSMinVersion != "" {
tlsvers, ok := TLSLookup[c.TLSMinVersion]
if !ok {
return nil, fmt.Errorf("TLSMinVersion: value %s not supported, please specify one of [tls10,tls11,tls12]", c.TLSMinVersion)
}
tlsConfig.MinVersion = tlsvers
}
return tlsConfig, nil
}
@ -310,5 +329,14 @@ func (c *Config) IncomingTLSConfig() (*tls.Config, error) {
return nil, fmt.Errorf("VerifyIncoming set, and no Cert/Key pair provided!")
}
}
// Check if a minimum TLS version was set
if c.TLSMinVersion != "" {
tlsvers, ok := TLSLookup[c.TLSMinVersion]
if !ok {
return nil, fmt.Errorf("TLSMinVersion: value %s not supported, please specify one of [tls10,tls11,tls12]", c.TLSMinVersion)
}
tlsConfig.MinVersion = tlsvers
}
return tlsConfig, nil
}

View file

@ -183,6 +183,27 @@ func TestConfig_OutgoingTLS_WithKeyPair(t *testing.T) {
}
}
func TestConfig_OutgoingTLS_TLSMinVersion(t *testing.T) {
tlsVersions := []string{"tls10", "tls11", "tls12"}
for _, version := range tlsVersions {
conf := &Config{
VerifyOutgoing: true,
CAFile: "../test/ca/root.cer",
TLSMinVersion: version,
}
tls, err := conf.OutgoingTLSConfig()
if err != nil {
t.Fatalf("err: %v", err)
}
if tls == nil {
t.Fatalf("expected config")
}
if tls.MinVersion != TLSLookup[version] {
t.Fatalf("expected tls min version: %v, %v", tls.MinVersion, TLSLookup[version])
}
}
}
func startTLSServer(config *Config) (net.Conn, chan error) {
errc := make(chan error, 1)
@ -450,3 +471,26 @@ func TestConfig_IncomingTLS_NoVerify(t *testing.T) {
t.Fatalf("unexpected client cert")
}
}
func TestConfig_IncomingTLS_TLSMinVersion(t *testing.T) {
tlsVersions := []string{"tls10", "tls11", "tls12"}
for _, version := range tlsVersions {
conf := &Config{
VerifyIncoming: true,
CAFile: "../test/ca/root.cer",
CertFile: "../test/key/ourdomain.cer",
KeyFile: "../test/key/ourdomain.key",
TLSMinVersion: version,
}
tls, err := conf.IncomingTLSConfig()
if err != nil {
t.Fatalf("err: %v", err)
}
if tls == nil {
t.Fatalf("expected config")
}
if tls.MinVersion != TLSLookup[version] {
t.Fatalf("expected tls min version: %v, %v", tls.MinVersion, TLSLookup[version])
}
}
}

View file

@ -961,6 +961,11 @@ Consul will not enable TLS for the HTTP API unless the `https` port has been ass
[`enable_syslog`](#enable_syslog) is provided, this controls to which
facility messages are sent. By default, `LOCAL0` will be used.
* <a name="tls_min_version"></a><a href="#tls_min_version">`tls_min_version`</a> Added in Consul
0.7.4, this specifies the minimum supported version of TLS. Accepted values are "tls10", "tls11"
or "tls12". This defaults to "tls10". WARNING: TLS 1.1 and lower are generally considered less
secure; avoid using these if possible. This will be changed to default to "tls12" in Consul 0.8.0.
* <a name="translate_wan_addrs"</a><a href="#translate_wan_addrs">`translate_wan_addrs`</a> If
set to true, Consul will prefer a node's configured <a href="#_advertise-wan">WAN address</a>
when servicing DNS and HTTP requests for a node in a remote datacenter. This allows the node to