mirror of https://github.com/hashicorp/consul
Add TLS cipher suite options and CA path support (#2963)
This patch adds options to configure the available TLS cipher suites and adds support for a path for multiple CA certificates. Fixes #2959pull/2949/merge
parent
4af5b22669
commit
b70e419aeb
|
@ -453,11 +453,14 @@ func (a *Agent) consulConfig() *consul.Config {
|
||||||
base.VerifyOutgoing = a.config.VerifyOutgoing
|
base.VerifyOutgoing = a.config.VerifyOutgoing
|
||||||
base.VerifyServerHostname = a.config.VerifyServerHostname
|
base.VerifyServerHostname = a.config.VerifyServerHostname
|
||||||
base.CAFile = a.config.CAFile
|
base.CAFile = a.config.CAFile
|
||||||
|
base.CAPath = a.config.CAPath
|
||||||
base.CertFile = a.config.CertFile
|
base.CertFile = a.config.CertFile
|
||||||
base.KeyFile = a.config.KeyFile
|
base.KeyFile = a.config.KeyFile
|
||||||
base.ServerName = a.config.ServerName
|
base.ServerName = a.config.ServerName
|
||||||
base.Domain = a.config.Domain
|
base.Domain = a.config.Domain
|
||||||
base.TLSMinVersion = a.config.TLSMinVersion
|
base.TLSMinVersion = a.config.TLSMinVersion
|
||||||
|
base.TLSCipherSuites = a.config.TLSCipherSuites
|
||||||
|
base.TLSPreferServerCipherSuites = a.config.TLSPreferServerCipherSuites
|
||||||
|
|
||||||
// Setup the ServerUp callback
|
// Setup the ServerUp callback
|
||||||
base.ServerUp = a.state.ConsulServerUp
|
base.ServerUp = a.state.ConsulServerUp
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
|
|
||||||
"github.com/hashicorp/consul/consul"
|
"github.com/hashicorp/consul/consul"
|
||||||
"github.com/hashicorp/consul/lib"
|
"github.com/hashicorp/consul/lib"
|
||||||
|
"github.com/hashicorp/consul/tlsutil"
|
||||||
"github.com/hashicorp/consul/types"
|
"github.com/hashicorp/consul/types"
|
||||||
"github.com/hashicorp/consul/watch"
|
"github.com/hashicorp/consul/watch"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
|
@ -469,6 +470,10 @@ type Config struct {
|
||||||
// or VerifyOutgoing to verify the TLS connection.
|
// or VerifyOutgoing to verify the TLS connection.
|
||||||
CAFile string `mapstructure:"ca_file"`
|
CAFile string `mapstructure:"ca_file"`
|
||||||
|
|
||||||
|
// CAPath is a path to a directory of certificate authority files. This is used with
|
||||||
|
// VerifyIncoming or VerifyOutgoing to verify the TLS connection.
|
||||||
|
CAPath string `mapstructure:"ca_path"`
|
||||||
|
|
||||||
// CertFile is used to provide a TLS certificate that is used for serving TLS connections.
|
// CertFile is used to provide a TLS certificate that is used for serving TLS connections.
|
||||||
// Must be provided to serve TLS connections.
|
// Must be provided to serve TLS connections.
|
||||||
CertFile string `mapstructure:"cert_file"`
|
CertFile string `mapstructure:"cert_file"`
|
||||||
|
@ -484,6 +489,14 @@ type Config struct {
|
||||||
// TLSMinVersion is used to set the minimum TLS version used for TLS connections.
|
// TLSMinVersion is used to set the minimum TLS version used for TLS connections.
|
||||||
TLSMinVersion string `mapstructure:"tls_min_version"`
|
TLSMinVersion string `mapstructure:"tls_min_version"`
|
||||||
|
|
||||||
|
// TLSCipherSuites is used to specify the list of supported ciphersuites.
|
||||||
|
TLSCipherSuites []uint16 `mapstructure:"-" json:"-"`
|
||||||
|
TLSCipherSuitesRaw string `mapstructure:"tls_cipher_suites"`
|
||||||
|
|
||||||
|
// TLSPreferServerCipherSuites specifies whether to prefer the server's ciphersuite
|
||||||
|
// over the client ciphersuites.
|
||||||
|
TLSPreferServerCipherSuites bool `mapstructure:"tls_prefer_server_cipher_suites"`
|
||||||
|
|
||||||
// StartJoin is a list of addresses to attempt to join when the
|
// StartJoin is a list of addresses to attempt to join when the
|
||||||
// agent starts. If Serf is unable to communicate with any of these
|
// agent starts. If Serf is unable to communicate with any of these
|
||||||
// addresses, then the agent will error and exit.
|
// addresses, then the agent will error and exit.
|
||||||
|
@ -1178,6 +1191,14 @@ func DecodeConfig(r io.Reader) (*Config, error) {
|
||||||
return nil, fmt.Errorf("Performance.RaftMultiplier must be <= %d", consul.MaxRaftMultiplier)
|
return nil, fmt.Errorf("Performance.RaftMultiplier must be <= %d", consul.MaxRaftMultiplier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if raw := result.TLSCipherSuitesRaw; raw != "" {
|
||||||
|
ciphers, err := tlsutil.ParseCiphers(raw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("TLSCipherSuites invalid: %v", err)
|
||||||
|
}
|
||||||
|
result.TLSCipherSuites = ciphers
|
||||||
|
}
|
||||||
|
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1517,6 +1538,9 @@ func MergeConfig(a, b *Config) *Config {
|
||||||
if b.CAFile != "" {
|
if b.CAFile != "" {
|
||||||
result.CAFile = b.CAFile
|
result.CAFile = b.CAFile
|
||||||
}
|
}
|
||||||
|
if b.CAPath != "" {
|
||||||
|
result.CAPath = b.CAPath
|
||||||
|
}
|
||||||
if b.CertFile != "" {
|
if b.CertFile != "" {
|
||||||
result.CertFile = b.CertFile
|
result.CertFile = b.CertFile
|
||||||
}
|
}
|
||||||
|
@ -1529,6 +1553,12 @@ func MergeConfig(a, b *Config) *Config {
|
||||||
if b.TLSMinVersion != "" {
|
if b.TLSMinVersion != "" {
|
||||||
result.TLSMinVersion = b.TLSMinVersion
|
result.TLSMinVersion = b.TLSMinVersion
|
||||||
}
|
}
|
||||||
|
if len(b.TLSCipherSuites) != 0 {
|
||||||
|
result.TLSCipherSuites = append(result.TLSCipherSuites, b.TLSCipherSuites...)
|
||||||
|
}
|
||||||
|
if b.TLSPreferServerCipherSuites {
|
||||||
|
result.TLSPreferServerCipherSuites = true
|
||||||
|
}
|
||||||
if b.Checks != nil {
|
if b.Checks != nil {
|
||||||
result.Checks = append(result.Checks, b.Checks...)
|
result.Checks = append(result.Checks, b.Checks...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package agent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
|
@ -354,7 +355,8 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TLS
|
// TLS
|
||||||
input = `{"verify_incoming": true, "verify_outgoing": true, "verify_server_hostname": true, "tls_min_version": "tls12"}`
|
input = `{"verify_incoming": true, "verify_outgoing": true, "verify_server_hostname": true, "tls_min_version": "tls12",
|
||||||
|
"tls_cipher_suites": "TLS_RSA_WITH_AES_256_CBC_SHA", "tls_prefer_server_cipher_suites": true}`
|
||||||
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
|
@ -376,8 +378,16 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
t.Fatalf("bad: %#v", config)
|
t.Fatalf("bad: %#v", config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(config.TLSCipherSuites) != 1 || config.TLSCipherSuites[0] != tls.TLS_RSA_WITH_AES_256_CBC_SHA {
|
||||||
|
t.Fatalf("bad: %#v", config)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !config.TLSPreferServerCipherSuites {
|
||||||
|
t.Fatalf("bad: %#v", config)
|
||||||
|
}
|
||||||
|
|
||||||
// TLS keys
|
// TLS keys
|
||||||
input = `{"ca_file": "my/ca/file", "cert_file": "my.cert", "key_file": "key.pem", "server_name": "example.com"}`
|
input = `{"ca_file": "my/ca/file", "ca_path":"my/ca/path", "cert_file": "my.cert", "key_file": "key.pem", "server_name": "example.com"}`
|
||||||
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
config, err = DecodeConfig(bytes.NewReader([]byte(input)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
|
@ -386,6 +396,9 @@ func TestDecodeConfig(t *testing.T) {
|
||||||
if config.CAFile != "my/ca/file" {
|
if config.CAFile != "my/ca/file" {
|
||||||
t.Fatalf("bad: %#v", config)
|
t.Fatalf("bad: %#v", config)
|
||||||
}
|
}
|
||||||
|
if config.CAPath != "my/ca/path" {
|
||||||
|
t.Fatalf("bad: %#v", config)
|
||||||
|
}
|
||||||
if config.CertFile != "my.cert" {
|
if config.CertFile != "my.cert" {
|
||||||
t.Fatalf("bad: %#v", config)
|
t.Fatalf("bad: %#v", config)
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,14 +56,17 @@ func NewHTTPServers(agent *Agent, config *Config, logOutput io.Writer) ([]*HTTPS
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConf := &tlsutil.Config{
|
tlsConf := &tlsutil.Config{
|
||||||
VerifyIncoming: config.VerifyIncoming,
|
VerifyIncoming: config.VerifyIncoming,
|
||||||
VerifyOutgoing: config.VerifyOutgoing,
|
VerifyOutgoing: config.VerifyOutgoing,
|
||||||
CAFile: config.CAFile,
|
CAFile: config.CAFile,
|
||||||
CertFile: config.CertFile,
|
CAPath: config.CAPath,
|
||||||
KeyFile: config.KeyFile,
|
CertFile: config.CertFile,
|
||||||
NodeName: config.NodeName,
|
KeyFile: config.KeyFile,
|
||||||
ServerName: config.ServerName,
|
NodeName: config.NodeName,
|
||||||
TLSMinVersion: config.TLSMinVersion,
|
ServerName: config.ServerName,
|
||||||
|
TLSMinVersion: config.TLSMinVersion,
|
||||||
|
CipherSuites: config.TLSCipherSuites,
|
||||||
|
PreferServerCipherSuites: config.TLSPreferServerCipherSuites,
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConfig, err := tlsConf.IncomingTLSConfig()
|
tlsConfig, err := tlsConf.IncomingTLSConfig()
|
||||||
|
|
|
@ -142,6 +142,10 @@ type Config struct {
|
||||||
// or VerifyOutgoing to verify the TLS connection.
|
// or VerifyOutgoing to verify the TLS connection.
|
||||||
CAFile string
|
CAFile string
|
||||||
|
|
||||||
|
// CAPath is a path to a directory of certificate authority files. This is used with
|
||||||
|
// VerifyIncoming or VerifyOutgoing to verify the TLS connection.
|
||||||
|
CAPath string
|
||||||
|
|
||||||
// CertFile is used to provide a TLS certificate that is used for serving TLS connections.
|
// CertFile is used to provide a TLS certificate that is used for serving TLS connections.
|
||||||
// Must be provided to serve TLS connections.
|
// Must be provided to serve TLS connections.
|
||||||
CertFile string
|
CertFile string
|
||||||
|
@ -157,6 +161,13 @@ type Config struct {
|
||||||
// TLSMinVersion is used to set the minimum TLS version used for TLS connections.
|
// TLSMinVersion is used to set the minimum TLS version used for TLS connections.
|
||||||
TLSMinVersion string
|
TLSMinVersion string
|
||||||
|
|
||||||
|
// TLSCipherSuites is used to specify the list of supported ciphersuites.
|
||||||
|
TLSCipherSuites []uint16
|
||||||
|
|
||||||
|
// TLSPreferServerCipherSuites specifies whether to prefer the server's ciphersuite
|
||||||
|
// over the client ciphersuites.
|
||||||
|
TLSPreferServerCipherSuites bool
|
||||||
|
|
||||||
// RejoinAfterLeave controls our interaction with Serf.
|
// RejoinAfterLeave controls our interaction with Serf.
|
||||||
// When set to false (default), a leave causes a Consul to not rejoin
|
// 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
|
// the cluster until an explicit join is received. If this is set to
|
||||||
|
@ -421,16 +432,18 @@ func (c *Config) ScaleRaft(raftMultRaw uint) {
|
||||||
// tlsConfig maps this config into a tlsutil config.
|
// tlsConfig maps this config into a tlsutil config.
|
||||||
func (c *Config) tlsConfig() *tlsutil.Config {
|
func (c *Config) tlsConfig() *tlsutil.Config {
|
||||||
tlsConf := &tlsutil.Config{
|
tlsConf := &tlsutil.Config{
|
||||||
VerifyIncoming: c.VerifyIncoming,
|
VerifyIncoming: c.VerifyIncoming,
|
||||||
VerifyOutgoing: c.VerifyOutgoing,
|
VerifyOutgoing: c.VerifyOutgoing,
|
||||||
VerifyServerHostname: c.VerifyServerHostname,
|
VerifyServerHostname: c.VerifyServerHostname,
|
||||||
CAFile: c.CAFile,
|
CAFile: c.CAFile,
|
||||||
CertFile: c.CertFile,
|
CAPath: c.CAPath,
|
||||||
KeyFile: c.KeyFile,
|
CertFile: c.CertFile,
|
||||||
NodeName: c.NodeName,
|
KeyFile: c.KeyFile,
|
||||||
ServerName: c.ServerName,
|
NodeName: c.NodeName,
|
||||||
Domain: c.Domain,
|
ServerName: c.ServerName,
|
||||||
TLSMinVersion: c.TLSMinVersion,
|
Domain: c.Domain,
|
||||||
|
TLSMinVersion: c.TLSMinVersion,
|
||||||
|
PreferServerCipherSuites: c.TLSPreferServerCipherSuites,
|
||||||
}
|
}
|
||||||
return tlsConf
|
return tlsConf
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-rootcerts"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DCWrapper is a function that is used to wrap a non-TLS connection
|
// DCWrapper is a function that is used to wrap a non-TLS connection
|
||||||
|
@ -51,6 +53,10 @@ type Config struct {
|
||||||
// or VerifyOutgoing to verify the TLS connection.
|
// or VerifyOutgoing to verify the TLS connection.
|
||||||
CAFile string
|
CAFile string
|
||||||
|
|
||||||
|
// CAPath is a path to a directory containing certificate authority files. This is used
|
||||||
|
// with VerifyIncoming or VerifyOutgoing to verify the TLS connection.
|
||||||
|
CAPath string
|
||||||
|
|
||||||
// CertFile is used to provide a TLS certificate that is used for serving TLS connections.
|
// CertFile is used to provide a TLS certificate that is used for serving TLS connections.
|
||||||
// Must be provided to serve TLS connections.
|
// Must be provided to serve TLS connections.
|
||||||
CertFile string
|
CertFile string
|
||||||
|
@ -71,6 +77,13 @@ type Config struct {
|
||||||
|
|
||||||
// TLSMinVersion is the minimum accepted TLS version that can be used.
|
// TLSMinVersion is the minimum accepted TLS version that can be used.
|
||||||
TLSMinVersion string
|
TLSMinVersion string
|
||||||
|
|
||||||
|
// CipherSuites is the list of TLS cipher suites to use.
|
||||||
|
CipherSuites []uint16
|
||||||
|
|
||||||
|
// PreferServerCipherSuites specifies whether to prefer the server's ciphersuite
|
||||||
|
// over the client ciphersuites.
|
||||||
|
PreferServerCipherSuites bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppendCA opens and parses the CA file and adds the certificates to
|
// AppendCA opens and parses the CA file and adds the certificates to
|
||||||
|
@ -130,15 +143,24 @@ func (c *Config) OutgoingTLSConfig() (*tls.Config, error) {
|
||||||
tlsConfig.ServerName = "VerifyServerHostname"
|
tlsConfig.ServerName = "VerifyServerHostname"
|
||||||
tlsConfig.InsecureSkipVerify = false
|
tlsConfig.InsecureSkipVerify = false
|
||||||
}
|
}
|
||||||
|
if len(c.CipherSuites) != 0 {
|
||||||
|
tlsConfig.CipherSuites = c.CipherSuites
|
||||||
|
}
|
||||||
|
if c.PreferServerCipherSuites {
|
||||||
|
tlsConfig.PreferServerCipherSuites = true
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure we have a CA if VerifyOutgoing is set
|
// Ensure we have a CA if VerifyOutgoing is set
|
||||||
if c.VerifyOutgoing && c.CAFile == "" {
|
if c.VerifyOutgoing && c.CAFile == "" && c.CAPath == "" {
|
||||||
return nil, fmt.Errorf("VerifyOutgoing set, and no CA certificate provided!")
|
return nil, fmt.Errorf("VerifyOutgoing set, and no CA certificate provided!")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the CA cert if any
|
// Parse the CA certs if any
|
||||||
err := c.AppendCA(tlsConfig.RootCAs)
|
rootConfig := &rootcerts.Config{
|
||||||
if err != nil {
|
CAFile: c.CAFile,
|
||||||
|
CAPath: c.CAPath,
|
||||||
|
}
|
||||||
|
if err := rootcerts.ConfigureTLS(tlsConfig, rootConfig); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,10 +327,27 @@ func (c *Config) IncomingTLSConfig() (*tls.Config, error) {
|
||||||
tlsConfig.ServerName = c.NodeName
|
tlsConfig.ServerName = c.NodeName
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the CA cert if any
|
// Set the cipher suites
|
||||||
err := c.AppendCA(tlsConfig.ClientCAs)
|
if len(c.CipherSuites) != 0 {
|
||||||
if err != nil {
|
tlsConfig.CipherSuites = c.CipherSuites
|
||||||
return nil, err
|
}
|
||||||
|
if c.PreferServerCipherSuites {
|
||||||
|
tlsConfig.PreferServerCipherSuites = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the CA certs if any
|
||||||
|
if c.CAFile != "" {
|
||||||
|
pool, err := rootcerts.LoadCAFile(c.CAFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tlsConfig.ClientCAs = pool
|
||||||
|
} else if c.CAPath != "" {
|
||||||
|
pool, err := rootcerts.LoadCAPath(c.CAPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tlsConfig.ClientCAs = pool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add cert/key
|
// Add cert/key
|
||||||
|
@ -322,7 +361,7 @@ func (c *Config) IncomingTLSConfig() (*tls.Config, error) {
|
||||||
// Check if we require verification
|
// Check if we require verification
|
||||||
if c.VerifyIncoming {
|
if c.VerifyIncoming {
|
||||||
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
||||||
if c.CAFile == "" {
|
if c.CAFile == "" && c.CAPath == "" {
|
||||||
return nil, fmt.Errorf("VerifyIncoming set, and no CA certificate provided!")
|
return nil, fmt.Errorf("VerifyIncoming set, and no CA certificate provided!")
|
||||||
}
|
}
|
||||||
if cert == nil {
|
if cert == nil {
|
||||||
|
@ -340,3 +379,43 @@ func (c *Config) IncomingTLSConfig() (*tls.Config, error) {
|
||||||
}
|
}
|
||||||
return tlsConfig, nil
|
return tlsConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseCiphers parse ciphersuites from the comma-separated string into recognized slice
|
||||||
|
func ParseCiphers(cipherStr string) ([]uint16, error) {
|
||||||
|
suites := []uint16{}
|
||||||
|
|
||||||
|
cipherStr = strings.TrimSpace(cipherStr)
|
||||||
|
if cipherStr == "" {
|
||||||
|
return []uint16{}, nil
|
||||||
|
}
|
||||||
|
ciphers := strings.Split(cipherStr, ",")
|
||||||
|
|
||||||
|
cipherMap := map[string]uint16{
|
||||||
|
"TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||||
|
"TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
"TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
"TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
"TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
"TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||||
|
"TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
||||||
|
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
}
|
||||||
|
for _, cipher := range ciphers {
|
||||||
|
if v, ok := cipherMap[cipher]; ok {
|
||||||
|
suites = append(suites, v)
|
||||||
|
} else {
|
||||||
|
return suites, fmt.Errorf("unsupported cipher %q", cipher)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return suites, nil
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/yamux"
|
"github.com/hashicorp/yamux"
|
||||||
|
@ -37,6 +39,20 @@ func TestConfig_CACertificate_Valid(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfig_CAPath_Valid(t *testing.T) {
|
||||||
|
conf := &Config{
|
||||||
|
CAPath: "../test/ca_path",
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConf, err := conf.IncomingTLSConfig()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %v", err)
|
||||||
|
}
|
||||||
|
if len(tlsConf.ClientCAs.Subjects()) != 2 {
|
||||||
|
t.Fatalf("expected certs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestConfig_KeyPair_None(t *testing.T) {
|
func TestConfig_KeyPair_None(t *testing.T) {
|
||||||
conf := &Config{}
|
conf := &Config{}
|
||||||
cert, err := conf.KeyPair()
|
cert, err := conf.KeyPair()
|
||||||
|
@ -494,3 +510,46 @@ func TestConfig_IncomingTLS_TLSMinVersion(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfig_ParseCiphers(t *testing.T) {
|
||||||
|
testOk := strings.Join([]string{
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
}, ",")
|
||||||
|
ciphers := []uint16{
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
}
|
||||||
|
v, err := ParseCiphers(testOk)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if got, want := v, ciphers; !reflect.DeepEqual(got, want) {
|
||||||
|
t.Fatalf("got ciphers %#v want %#v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
testBad := "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,cipherX"
|
||||||
|
if _, err := ParseCiphers(testBad); err == nil {
|
||||||
|
t.Fatal("should fail on unsupported cipherX")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -617,6 +617,11 @@ Consul will not enable TLS for the HTTP API unless the `https` port has been ass
|
||||||
server connections with the appropriate [`verify_incoming`](#verify_incoming) or
|
server connections with the appropriate [`verify_incoming`](#verify_incoming) or
|
||||||
[`verify_outgoing`](#verify_outgoing) flags.
|
[`verify_outgoing`](#verify_outgoing) flags.
|
||||||
|
|
||||||
|
* <a name="ca_path"></a><a href="#ca_path">`ca_path`</a> This provides a path to a directory of PEM-encoded
|
||||||
|
certificate authority files. These certificate authorities are used to check the authenticity of client and
|
||||||
|
server connections with the appropriate [`verify_incoming`](#verify_incoming) or
|
||||||
|
[`verify_outgoing`](#verify_outgoing) flags.
|
||||||
|
|
||||||
* <a name="cert_file"></a><a href="#cert_file">`cert_file`</a> This provides a file path to a
|
* <a name="cert_file"></a><a href="#cert_file">`cert_file`</a> This provides a file path to a
|
||||||
PEM-encoded certificate. The certificate is provided to clients or servers to verify the agent's
|
PEM-encoded certificate. The certificate is provided to clients or servers to verify the agent's
|
||||||
authenticity. It must be provided along with [`key_file`](#key_file).
|
authenticity. It must be provided along with [`key_file`](#key_file).
|
||||||
|
@ -1028,6 +1033,14 @@ Consul will not enable TLS for the HTTP API unless the `https` port has been ass
|
||||||
or "tls12". This defaults to "tls10". WARNING: TLS 1.1 and lower are generally considered less
|
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.
|
secure; avoid using these if possible. This will be changed to default to "tls12" in Consul 0.8.0.
|
||||||
|
|
||||||
|
* <a name="tls_cipher_suites"></a><a href="#tls_cipher_suites">`tls_cipher_suites`</a> Added in Consul
|
||||||
|
0.8.2, this specifies the list of supported ciphersuites as a comma-separated-list. The list of all
|
||||||
|
available ciphersuites is available in the [Golang TLS documentation](https://golang.org/src/crypto/tls/cipher_suites.go).
|
||||||
|
|
||||||
|
* <a name="tls_prefer_server_cipher_suites"></a><a href="#tls_prefer_server_cipher_suites">
|
||||||
|
`tls_prefer_server_cipher_suites`</a> Added in Consul 0.8.2, this will cause Consul to prefer the
|
||||||
|
server's ciphersuite over the client ciphersuites.
|
||||||
|
|
||||||
* <a name="translate_wan_addrs"</a><a href="#translate_wan_addrs">`translate_wan_addrs`</a> If
|
* <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>
|
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
|
when servicing DNS and HTTP requests for a node in a remote datacenter. This allows the node to
|
||||||
|
|
Loading…
Reference in New Issue