Merge pull request #4338 from hashicorp/tls_prefer_server_cipher_suites

Add support for tls PreferServerCipherSuites
This commit is contained in:
Alex Dadgar 2018-05-30 17:25:17 +00:00 committed by GitHub
commit ad3dbe8ed0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 176 additions and 42 deletions

View File

@ -2,6 +2,7 @@
IMPROVEMENTS: IMPROVEMENTS:
* core: Updated serf library to improve how leave intents are handled [[GH-4278](https://github.com/hashicorp/nomad/issues/4278)] * core: Updated serf library to improve how leave intents are handled [[GH-4278](https://github.com/hashicorp/nomad/issues/4278)]
* core: Added TLS configuration option to prefer server's ciphersuites over clients[[GH-4338](https://github.com/hashicorp/nomad/issues/4338)]
* core: Add the option for operators to configure TLS versions and allowed * core: Add the option for operators to configure TLS versions and allowed
cipher suites. Default is a subset of safe ciphers and TLS 1.2 [[GH-4269](https://github.com/hashicorp/nomad/pull/4269)] cipher suites. Default is a subset of safe ciphers and TLS 1.2 [[GH-4269](https://github.com/hashicorp/nomad/pull/4269)]
* core: Add a new [progress_deadline](https://www.nomadproject.io/docs/job-specification/update.html#progress_deadline) parameter to * core: Add a new [progress_deadline](https://www.nomadproject.io/docs/job-specification/update.html#progress_deadline) parameter to

View File

@ -156,6 +156,9 @@ tls {
key_file = "pipe" key_file = "pipe"
rpc_upgrade_mode = true rpc_upgrade_mode = true
verify_https_client = true verify_https_client = true
tls_prefer_server_cipher_suites = true
tls_cipher_suites = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
tls_min_version = "tls12"
} }
sentinel { sentinel {
import "foo" { import "foo" {

View File

@ -763,6 +763,7 @@ func parseTLSConfig(result **config.TLSConfig, list *ast.ObjectList) error {
"verify_https_client", "verify_https_client",
"tls_cipher_suites", "tls_cipher_suites",
"tls_min_version", "tls_min_version",
"tls_prefer_server_cipher_suites",
} }
if err := helper.CheckHCLKeys(listVal, valid); err != nil { if err := helper.CheckHCLKeys(listVal, valid); err != nil {

View File

@ -167,14 +167,17 @@ func TestConfig_Parse(t *testing.T) {
Token: "12345", Token: "12345",
}, },
TLSConfig: &config.TLSConfig{ TLSConfig: &config.TLSConfig{
EnableHTTP: true, EnableHTTP: true,
EnableRPC: true, EnableRPC: true,
VerifyServerHostname: true, VerifyServerHostname: true,
CAFile: "foo", CAFile: "foo",
CertFile: "bar", CertFile: "bar",
KeyFile: "pipe", KeyFile: "pipe",
RPCUpgradeMode: true, RPCUpgradeMode: true,
VerifyHTTPSClient: true, VerifyHTTPSClient: true,
TLSPreferServerCipherSuites: true,
TLSCipherSuites: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
TLSMinVersion: "tls12",
}, },
HTTPAPIResponseHeaders: map[string]string{ HTTPAPIResponseHeaders: map[string]string{
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Origin": "*",

View File

@ -105,6 +105,12 @@ type Config struct {
// these values for acceptable safe alternatives. // these values for acceptable safe alternatives.
CipherSuites []uint16 CipherSuites []uint16
// PreferServerCipherSuites controls whether the server selects the
// client's most preferred ciphersuite, or the server's most preferred
// ciphersuite. If true then the server's preference, as expressed in
// the order of elements in CipherSuites, is used.
PreferServerCipherSuites bool
// MinVersion contains the minimum SSL/TLS version that is accepted. // MinVersion contains the minimum SSL/TLS version that is accepted.
MinVersion uint16 MinVersion uint16
} }
@ -121,15 +127,16 @@ func NewTLSConfiguration(newConf *config.TLSConfig, verifyIncoming, verifyOutgoi
} }
return &Config{ return &Config{
VerifyIncoming: verifyIncoming, VerifyIncoming: verifyIncoming,
VerifyOutgoing: verifyOutgoing, VerifyOutgoing: verifyOutgoing,
VerifyServerHostname: newConf.VerifyServerHostname, VerifyServerHostname: newConf.VerifyServerHostname,
CAFile: newConf.CAFile, CAFile: newConf.CAFile,
CertFile: newConf.CertFile, CertFile: newConf.CertFile,
KeyFile: newConf.KeyFile, KeyFile: newConf.KeyFile,
KeyLoader: newConf.GetKeyLoader(), KeyLoader: newConf.GetKeyLoader(),
CipherSuites: ciphers, CipherSuites: ciphers,
MinVersion: minVersion, MinVersion: minVersion,
PreferServerCipherSuites: newConf.TLSPreferServerCipherSuites,
}, nil }, nil
} }
@ -184,10 +191,11 @@ func (c *Config) OutgoingTLSConfig() (*tls.Config, error) {
} }
// Create the tlsConfig // Create the tlsConfig
tlsConfig := &tls.Config{ tlsConfig := &tls.Config{
RootCAs: x509.NewCertPool(), RootCAs: x509.NewCertPool(),
InsecureSkipVerify: true, InsecureSkipVerify: true,
CipherSuites: c.CipherSuites, CipherSuites: c.CipherSuites,
MinVersion: c.MinVersion, MinVersion: c.MinVersion,
PreferServerCipherSuites: c.PreferServerCipherSuites,
} }
if c.VerifyServerHostname { if c.VerifyServerHostname {
tlsConfig.InsecureSkipVerify = false tlsConfig.InsecureSkipVerify = false
@ -304,10 +312,11 @@ func WrapTLSClient(conn net.Conn, tlsConfig *tls.Config) (net.Conn, error) {
func (c *Config) IncomingTLSConfig() (*tls.Config, error) { func (c *Config) IncomingTLSConfig() (*tls.Config, error) {
// Create the tlsConfig // Create the tlsConfig
tlsConfig := &tls.Config{ tlsConfig := &tls.Config{
ClientCAs: x509.NewCertPool(), ClientCAs: x509.NewCertPool(),
ClientAuth: tls.NoClientCert, ClientAuth: tls.NoClientCert,
CipherSuites: c.CipherSuites, CipherSuites: c.CipherSuites,
MinVersion: c.MinVersion, MinVersion: c.MinVersion,
PreferServerCipherSuites: c.PreferServerCipherSuites,
} }
// Parse the CA cert if any // Parse the CA cert if any

View File

@ -167,6 +167,60 @@ func TestConfig_OutgoingTLS_WithKeyPair(t *testing.T) {
assert.NotNil(cert) assert.NotNil(cert)
} }
func TestConfig_OutgoingTLS_PreferServerCipherSuites(t *testing.T) {
require := require.New(t)
{
conf := &Config{
VerifyOutgoing: true,
CAFile: cacert,
}
tlsConfig, err := conf.OutgoingTLSConfig()
require.Nil(err)
require.Equal(tlsConfig.PreferServerCipherSuites, false)
}
{
conf := &Config{
VerifyOutgoing: true,
CAFile: cacert,
PreferServerCipherSuites: true,
}
tlsConfig, err := conf.OutgoingTLSConfig()
require.Nil(err)
require.Equal(tlsConfig.PreferServerCipherSuites, true)
}
}
func TestConfig_OutgoingTLS_TLSCipherSuites(t *testing.T) {
require := require.New(t)
{
defaultCiphers := []uint16{
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
}
conf := &Config{
VerifyOutgoing: true,
CAFile: cacert,
CipherSuites: defaultCiphers,
}
tlsConfig, err := conf.OutgoingTLSConfig()
require.Nil(err)
require.Equal(tlsConfig.CipherSuites, defaultCiphers)
}
{
conf := &Config{
VerifyOutgoing: true,
CAFile: cacert,
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305},
}
tlsConfig, err := conf.OutgoingTLSConfig()
require.Nil(err)
require.Equal(tlsConfig.CipherSuites, []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305})
}
}
func startTLSServer(config *Config) (net.Conn, chan error) { func startTLSServer(config *Config) (net.Conn, chan error) {
errc := make(chan error, 1) errc := make(chan error, 1)
@ -416,6 +470,51 @@ func TestConfig_IncomingTLS_NoVerify(t *testing.T) {
} }
} }
func TestConfig_IncomingTLS_PreferServerCipherSuites(t *testing.T) {
require := require.New(t)
{
conf := &Config{}
tlsConfig, err := conf.IncomingTLSConfig()
require.Nil(err)
require.Equal(tlsConfig.PreferServerCipherSuites, false)
}
{
conf := &Config{
PreferServerCipherSuites: true,
}
tlsConfig, err := conf.IncomingTLSConfig()
require.Nil(err)
require.Equal(tlsConfig.PreferServerCipherSuites, true)
}
}
func TestConfig_IncomingTLS_TLSCipherSuites(t *testing.T) {
require := require.New(t)
{
defaultCiphers := []uint16{
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
}
conf := &Config{
CipherSuites: defaultCiphers,
}
tlsConfig, err := conf.IncomingTLSConfig()
require.Nil(err)
require.Equal(tlsConfig.CipherSuites, defaultCiphers)
}
{
conf := &Config{
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305},
}
tlsConfig, err := conf.IncomingTLSConfig()
require.Nil(err)
require.Equal(tlsConfig.CipherSuites, []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305})
}
}
func TestConfig_ParseCiphers_Valid(t *testing.T) { func TestConfig_ParseCiphers_Valid(t *testing.T) {
require := require.New(t) require := require.New(t)

View File

@ -63,6 +63,12 @@ type TLSConfig struct {
// TLSMinVersion is used to set the minimum TLS version used for TLS // TLSMinVersion is used to set the minimum TLS version used for TLS
// connections. Should be either "tls10", "tls11", or "tls12". // connections. Should be either "tls10", "tls11", or "tls12".
TLSMinVersion string `mapstructure:"tls_min_version"` TLSMinVersion string `mapstructure:"tls_min_version"`
// TLSPreferServerCipherSuites controls whether the server selects the
// client's most preferred ciphersuite, or the server's most preferred
// ciphersuite. If true then the server's preference, as expressed in
// the order of elements in CipherSuites, is used.
TLSPreferServerCipherSuites bool `mapstructure:"tls_prefer_server_cipher_suites"`
} }
type KeyLoader struct { type KeyLoader struct {
@ -158,6 +164,8 @@ func (t *TLSConfig) Copy() *TLSConfig {
new.TLSCipherSuites = t.TLSCipherSuites new.TLSCipherSuites = t.TLSCipherSuites
new.TLSMinVersion = t.TLSMinVersion new.TLSMinVersion = t.TLSMinVersion
new.TLSPreferServerCipherSuites = t.TLSPreferServerCipherSuites
new.SetChecksum() new.SetChecksum()
return new return new
@ -211,6 +219,9 @@ func (t *TLSConfig) Merge(b *TLSConfig) *TLSConfig {
if b.TLSMinVersion != "" { if b.TLSMinVersion != "" {
result.TLSMinVersion = b.TLSMinVersion result.TLSMinVersion = b.TLSMinVersion
} }
if b.TLSPreferServerCipherSuites {
result.TLSPreferServerCipherSuites = true
}
return result return result
} }

View File

@ -15,14 +15,15 @@ func TestTLSConfig_Merge(t *testing.T) {
} }
b := &TLSConfig{ b := &TLSConfig{
EnableHTTP: true, EnableHTTP: true,
EnableRPC: true, EnableRPC: true,
VerifyServerHostname: true, VerifyServerHostname: true,
CAFile: "test-ca-file-2", CAFile: "test-ca-file-2",
CertFile: "test-cert-file-2", CertFile: "test-cert-file-2",
RPCUpgradeMode: true, RPCUpgradeMode: true,
TLSCipherSuites: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", TLSCipherSuites: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
TLSMinVersion: "tls12", TLSMinVersion: "tls12",
TLSPreferServerCipherSuites: true,
} }
new := a.Merge(b) new := a.Merge(b)
@ -173,10 +174,12 @@ func TestTLS_Copy(t *testing.T) {
fookey = "../../../helper/tlsutil/testdata/nomad-foo-key.pem" fookey = "../../../helper/tlsutil/testdata/nomad-foo-key.pem"
) )
a := &TLSConfig{ a := &TLSConfig{
CAFile: cafile, CAFile: cafile,
CertFile: foocert, CertFile: foocert,
KeyFile: fookey, KeyFile: fookey,
TLSCipherSuites: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", TLSCipherSuites: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
TLSMinVersion: "tls12",
TLSPreferServerCipherSuites: true,
} }
a.SetChecksum() a.SetChecksum()

View File

@ -58,14 +58,18 @@ the [Agent's Gossip and RPC Encryption](/docs/agent/encryption.html).
cluster is being upgraded to TLS, and removed after the migration is cluster is being upgraded to TLS, and removed after the migration is
complete. This allows the agent to accept both TLS and plaintext traffic. complete. This allows the agent to accept both TLS and plaintext traffic.
- `tls_cipher_suites` - Specifies the TLS cipher suites that will be used by - `tls_cipher_suites` `(array<string>: [])` - Specifies the TLS cipher suites
the agent. Known insecure ciphers are disabled (3DES and RC4). By default, that will be used by the agent. Known insecure ciphers are disabled (3DES and
an agent is configured to use TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, RC4). By default, an agent is configured to use
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, and TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, and
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384. TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384.
- `tls_min_version` - Specifies the minimum supported version of TLS. Accepted - `tls_min_version` `(string: "tls12")`- Specifies the minimum supported version
values are "tls10", "tls11", "tls12". Defaults to TLS 1.2. of TLS. Accepted values are "tls10", "tls11", "tls12".
- `tls_prefer_server_cipher_suites` `(bool: false)` - Specifies whether
TLS connections should prefer the server's ciphersuites over the client's.
- `verify_https_client` `(bool: false)` - Specifies agents should require - `verify_https_client` `(bool: false)` - Specifies agents should require
client certificates for all incoming HTTPS requests. The client certificates client certificates for all incoming HTTPS requests. The client certificates