Merge pull request #4338 from hashicorp/tls_prefer_server_cipher_suites
Add support for tls PreferServerCipherSuites
This commit is contained in:
commit
ad3dbe8ed0
|
@ -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
|
||||||
|
|
|
@ -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" {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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": "*",
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue