mirror of
https://github.com/status-im/consul.git
synced 2025-02-19 17:14:37 +00:00
Add separate option for verifying incoming HTTPS traffic (#2974)
* Add separate option for verifying incoming HTTPS traffic
This commit is contained in:
parent
84d6ac2d51
commit
cd56a5ebdd
132
api/api_test.go
132
api/api_test.go
@ -256,53 +256,111 @@ func TestSetupTLSConfig(t *testing.T) {
|
|||||||
|
|
||||||
func TestClientTLSOptions(t *testing.T) {
|
func TestClientTLSOptions(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
_, s := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
|
// Start a server that verifies incoming HTTPS connections
|
||||||
|
_, srvVerify := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
|
||||||
conf.CAFile = "../test/client_certs/rootca.crt"
|
conf.CAFile = "../test/client_certs/rootca.crt"
|
||||||
conf.CertFile = "../test/client_certs/server.crt"
|
conf.CertFile = "../test/client_certs/server.crt"
|
||||||
conf.KeyFile = "../test/client_certs/server.key"
|
conf.KeyFile = "../test/client_certs/server.key"
|
||||||
conf.VerifyIncoming = true
|
conf.VerifyIncomingHTTPS = true
|
||||||
})
|
})
|
||||||
defer s.Stop()
|
defer srvVerify.Stop()
|
||||||
|
|
||||||
// Set up a client without certs
|
// Start a server without VerifyIncomingHTTPS
|
||||||
clientWithoutCerts, err := NewClient(&Config{
|
_, srvNoVerify := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
|
||||||
Address: s.HTTPSAddr,
|
conf.CAFile = "../test/client_certs/rootca.crt"
|
||||||
Scheme: "https",
|
conf.CertFile = "../test/client_certs/server.crt"
|
||||||
TLSConfig: TLSConfig{
|
conf.KeyFile = "../test/client_certs/server.key"
|
||||||
Address: "consul.test",
|
conf.VerifyIncomingHTTPS = false
|
||||||
CAFile: "../test/client_certs/rootca.crt",
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
defer srvNoVerify.Stop()
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should fail
|
// Client without a cert
|
||||||
_, err = clientWithoutCerts.Agent().Self()
|
t.Run("client without cert, validation", func(t *testing.T) {
|
||||||
if err == nil || !strings.Contains(err.Error(), "bad certificate") {
|
client, err := NewClient(&Config{
|
||||||
t.Fatal(err)
|
Address: srvVerify.HTTPSAddr,
|
||||||
}
|
Scheme: "https",
|
||||||
|
TLSConfig: TLSConfig{
|
||||||
|
Address: "consul.test",
|
||||||
|
CAFile: "../test/client_certs/rootca.crt",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Set up a client with valid certs
|
// Should fail
|
||||||
clientWithCerts, err := NewClient(&Config{
|
_, err = client.Agent().Self()
|
||||||
Address: s.HTTPSAddr,
|
if err == nil || !strings.Contains(err.Error(), "bad certificate") {
|
||||||
Scheme: "https",
|
t.Fatal(err)
|
||||||
TLSConfig: TLSConfig{
|
}
|
||||||
Address: "consul.test",
|
|
||||||
CAFile: "../test/client_certs/rootca.crt",
|
|
||||||
CertFile: "../test/client_certs/client.crt",
|
|
||||||
KeyFile: "../test/client_certs/client.key",
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should succeed
|
// Client with a valid cert
|
||||||
_, err = clientWithCerts.Agent().Self()
|
t.Run("client with cert, validation", func(t *testing.T) {
|
||||||
if err != nil {
|
client, err := NewClient(&Config{
|
||||||
t.Fatal(err)
|
Address: srvVerify.HTTPSAddr,
|
||||||
}
|
Scheme: "https",
|
||||||
|
TLSConfig: TLSConfig{
|
||||||
|
Address: "consul.test",
|
||||||
|
CAFile: "../test/client_certs/rootca.crt",
|
||||||
|
CertFile: "../test/client_certs/client.crt",
|
||||||
|
KeyFile: "../test/client_certs/client.key",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should succeed
|
||||||
|
_, err = client.Agent().Self()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Client without a cert
|
||||||
|
t.Run("client without cert, no validation", func(t *testing.T) {
|
||||||
|
client, err := NewClient(&Config{
|
||||||
|
Address: srvNoVerify.HTTPSAddr,
|
||||||
|
Scheme: "https",
|
||||||
|
TLSConfig: TLSConfig{
|
||||||
|
Address: "consul.test",
|
||||||
|
CAFile: "../test/client_certs/rootca.crt",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should succeed
|
||||||
|
_, err = client.Agent().Self()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Client with a valid cert
|
||||||
|
t.Run("client with cert, no validation", func(t *testing.T) {
|
||||||
|
client, err := NewClient(&Config{
|
||||||
|
Address: srvNoVerify.HTTPSAddr,
|
||||||
|
Scheme: "https",
|
||||||
|
TLSConfig: TLSConfig{
|
||||||
|
Address: "consul.test",
|
||||||
|
CAFile: "../test/client_certs/rootca.crt",
|
||||||
|
CertFile: "../test/client_certs/client.crt",
|
||||||
|
KeyFile: "../test/client_certs/client.key",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should succeed
|
||||||
|
_, err = client.Agent().Self()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetQueryOptions(t *testing.T) {
|
func TestSetQueryOptions(t *testing.T) {
|
||||||
|
@ -449,7 +449,7 @@ func (a *Agent) consulConfig() *consul.Config {
|
|||||||
a.config.Version, a.config.VersionPrerelease, revision)
|
a.config.Version, a.config.VersionPrerelease, revision)
|
||||||
|
|
||||||
// Copy the TLS configuration
|
// Copy the TLS configuration
|
||||||
base.VerifyIncoming = a.config.VerifyIncoming
|
base.VerifyIncoming = a.config.VerifyIncoming || a.config.VerifyIncomingRPC
|
||||||
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
|
||||||
|
@ -453,6 +453,16 @@ type Config struct {
|
|||||||
// must match a provided certificate authority. This can be used to force client auth.
|
// must match a provided certificate authority. This can be used to force client auth.
|
||||||
VerifyIncoming bool `mapstructure:"verify_incoming"`
|
VerifyIncoming bool `mapstructure:"verify_incoming"`
|
||||||
|
|
||||||
|
// VerifyIncomingRPC is used to verify the authenticity of incoming RPC connections.
|
||||||
|
// This means that TCP requests are forbidden, only allowing for TLS. TLS connections
|
||||||
|
// must match a provided certificate authority. This can be used to force client auth.
|
||||||
|
VerifyIncomingRPC bool `mapstructure:"verify_incoming_rpc"`
|
||||||
|
|
||||||
|
// VerifyIncomingHTTPS is used to verify the authenticity of incoming HTTPS connections.
|
||||||
|
// This means that TCP requests are forbidden, only allowing for TLS. TLS connections
|
||||||
|
// must match a provided certificate authority. This can be used to force client auth.
|
||||||
|
VerifyIncomingHTTPS bool `mapstructure:"verify_incoming_https"`
|
||||||
|
|
||||||
// VerifyOutgoing is used to verify the authenticity of outgoing connections.
|
// VerifyOutgoing is used to verify the authenticity of outgoing connections.
|
||||||
// This means that TLS requests are used. TLS connections must match a provided
|
// This means that TLS requests are used. TLS connections must match a provided
|
||||||
// certificate authority. This is used to verify authenticity of server nodes.
|
// certificate authority. This is used to verify authenticity of server nodes.
|
||||||
@ -1546,6 +1556,12 @@ func MergeConfig(a, b *Config) *Config {
|
|||||||
if b.VerifyIncoming {
|
if b.VerifyIncoming {
|
||||||
result.VerifyIncoming = true
|
result.VerifyIncoming = true
|
||||||
}
|
}
|
||||||
|
if b.VerifyIncomingRPC {
|
||||||
|
result.VerifyIncomingRPC = true
|
||||||
|
}
|
||||||
|
if b.VerifyIncomingHTTPS {
|
||||||
|
result.VerifyIncomingHTTPS = true
|
||||||
|
}
|
||||||
if b.VerifyOutgoing {
|
if b.VerifyOutgoing {
|
||||||
result.VerifyOutgoing = true
|
result.VerifyOutgoing = true
|
||||||
}
|
}
|
||||||
|
@ -355,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_incoming_rpc": true, "verify_incoming_https": 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}`
|
"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 {
|
||||||
@ -366,6 +367,14 @@ func TestDecodeConfig(t *testing.T) {
|
|||||||
t.Fatalf("bad: %#v", config)
|
t.Fatalf("bad: %#v", config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.VerifyIncomingRPC != true {
|
||||||
|
t.Fatalf("bad: %#v", config)
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.VerifyIncomingHTTPS != true {
|
||||||
|
t.Fatalf("bad: %#v", config)
|
||||||
|
}
|
||||||
|
|
||||||
if config.VerifyOutgoing != true {
|
if config.VerifyOutgoing != true {
|
||||||
t.Fatalf("bad: %#v", config)
|
t.Fatalf("bad: %#v", config)
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ func NewHTTPServers(agent *Agent, config *Config, logOutput io.Writer) ([]*HTTPS
|
|||||||
}
|
}
|
||||||
|
|
||||||
tlsConf := &tlsutil.Config{
|
tlsConf := &tlsutil.Config{
|
||||||
VerifyIncoming: config.VerifyIncoming,
|
VerifyIncoming: config.VerifyIncoming || config.VerifyIncomingHTTPS,
|
||||||
VerifyOutgoing: config.VerifyOutgoing,
|
VerifyOutgoing: config.VerifyOutgoing,
|
||||||
CAFile: config.CAFile,
|
CAFile: config.CAFile,
|
||||||
CAPath: config.CAPath,
|
CAPath: config.CAPath,
|
||||||
|
@ -56,32 +56,34 @@ type TestAddressConfig struct {
|
|||||||
|
|
||||||
// TestServerConfig is the main server configuration struct.
|
// TestServerConfig is the main server configuration struct.
|
||||||
type TestServerConfig struct {
|
type TestServerConfig struct {
|
||||||
NodeName string `json:"node_name"`
|
NodeName string `json:"node_name"`
|
||||||
NodeID string `json:"node_id"`
|
NodeID string `json:"node_id"`
|
||||||
NodeMeta map[string]string `json:"node_meta,omitempty"`
|
NodeMeta map[string]string `json:"node_meta,omitempty"`
|
||||||
Performance *TestPerformanceConfig `json:"performance,omitempty"`
|
Performance *TestPerformanceConfig `json:"performance,omitempty"`
|
||||||
Bootstrap bool `json:"bootstrap,omitempty"`
|
Bootstrap bool `json:"bootstrap,omitempty"`
|
||||||
Server bool `json:"server,omitempty"`
|
Server bool `json:"server,omitempty"`
|
||||||
DataDir string `json:"data_dir,omitempty"`
|
DataDir string `json:"data_dir,omitempty"`
|
||||||
Datacenter string `json:"datacenter,omitempty"`
|
Datacenter string `json:"datacenter,omitempty"`
|
||||||
DisableCheckpoint bool `json:"disable_update_check"`
|
DisableCheckpoint bool `json:"disable_update_check"`
|
||||||
LogLevel string `json:"log_level,omitempty"`
|
LogLevel string `json:"log_level,omitempty"`
|
||||||
Bind string `json:"bind_addr,omitempty"`
|
Bind string `json:"bind_addr,omitempty"`
|
||||||
Addresses *TestAddressConfig `json:"addresses,omitempty"`
|
Addresses *TestAddressConfig `json:"addresses,omitempty"`
|
||||||
Ports *TestPortConfig `json:"ports,omitempty"`
|
Ports *TestPortConfig `json:"ports,omitempty"`
|
||||||
RaftProtocol int `json:"raft_protocol,omitempty"`
|
RaftProtocol int `json:"raft_protocol,omitempty"`
|
||||||
ACLMasterToken string `json:"acl_master_token,omitempty"`
|
ACLMasterToken string `json:"acl_master_token,omitempty"`
|
||||||
ACLDatacenter string `json:"acl_datacenter,omitempty"`
|
ACLDatacenter string `json:"acl_datacenter,omitempty"`
|
||||||
ACLDefaultPolicy string `json:"acl_default_policy,omitempty"`
|
ACLDefaultPolicy string `json:"acl_default_policy,omitempty"`
|
||||||
ACLEnforceVersion8 bool `json:"acl_enforce_version_8"`
|
ACLEnforceVersion8 bool `json:"acl_enforce_version_8"`
|
||||||
Encrypt string `json:"encrypt,omitempty"`
|
Encrypt string `json:"encrypt,omitempty"`
|
||||||
CAFile string `json:"ca_file,omitempty"`
|
CAFile string `json:"ca_file,omitempty"`
|
||||||
CertFile string `json:"cert_file,omitempty"`
|
CertFile string `json:"cert_file,omitempty"`
|
||||||
KeyFile string `json:"key_file,omitempty"`
|
KeyFile string `json:"key_file,omitempty"`
|
||||||
VerifyIncoming bool `json:"verify_incoming,omitempty"`
|
VerifyIncoming bool `json:"verify_incoming,omitempty"`
|
||||||
VerifyOutgoing bool `json:"verify_outgoing,omitempty"`
|
VerifyIncomingRPC bool `json:"verify_incoming_rpc,omitempty"`
|
||||||
Stdout, Stderr io.Writer `json:"-"`
|
VerifyIncomingHTTPS bool `json:"verify_incoming_https,omitempty"`
|
||||||
Args []string `json:"-"`
|
VerifyOutgoing bool `json:"verify_outgoing,omitempty"`
|
||||||
|
Stdout, Stderr io.Writer `json:"-"`
|
||||||
|
Args []string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfigCallback is a function interface which can be
|
// ServerConfigCallback is a function interface which can be
|
||||||
|
@ -1052,18 +1052,30 @@ Consul will not enable TLS for the HTTP API unless the `https` port has been ass
|
|||||||
* <a name="verify_incoming"></a><a href="#verify_incoming">`verify_incoming`</a> - If
|
* <a name="verify_incoming"></a><a href="#verify_incoming">`verify_incoming`</a> - If
|
||||||
set to true, Consul requires that all incoming
|
set to true, Consul requires that all incoming
|
||||||
connections make use of TLS and that the client provides a certificate signed
|
connections make use of TLS and that the client provides a certificate signed
|
||||||
by the Certificate Authority from the [`ca_file`](#ca_file). By default, this is false, and
|
by a Certificate Authority from the [`ca_file`](#ca_file) or [`ca_path`](#ca_path).
|
||||||
Consul will not enforce the use of TLS or verify a client's authenticity. This
|
This applies to both server RPC and to the HTTPS API. By default, this is false, and
|
||||||
applies to both server RPC and to the HTTPS API. To enable the HTTPS API, you
|
Consul will not enforce the use of TLS or verify a client's authenticity.
|
||||||
must define an HTTPS port via the [`ports`](#ports) configuration. By default, HTTPS
|
|
||||||
is disabled.
|
* <a name="verify_incoming_rpc"></a><a href="#verify_incoming_rpc">`verify_incoming_rpc`</a> - If
|
||||||
|
set to true, Consul requires that all incoming RPC
|
||||||
|
connections make use of TLS and that the client provides a certificate signed
|
||||||
|
by a Certificate Authority from the [`ca_file`](#ca_file) or [`ca_path`](#ca_path). By default,
|
||||||
|
this is false, and Consul will not enforce the use of TLS or verify a client's authenticity.
|
||||||
|
|
||||||
|
* <a name="verify_incoming_https"></a><a href="#verify_incoming_https">`verify_incoming_https`</a> - If
|
||||||
|
set to true, Consul requires that all incoming HTTPS
|
||||||
|
connections make use of TLS and that the client provides a certificate signed
|
||||||
|
by a Certificate Authority from the [`ca_file`](#ca_file) or [`ca_path`](#ca_path). By default,
|
||||||
|
this is false, and Consul will not enforce the use of TLS or verify a client's authenticity. To
|
||||||
|
enable the HTTPS API, you must define an HTTPS port via the [`ports`](#ports) configuration. By
|
||||||
|
default, HTTPS is disabled.
|
||||||
|
|
||||||
* <a name="verify_outgoing"></a><a href="#verify_outgoing">`verify_outgoing`</a> - If set to
|
* <a name="verify_outgoing"></a><a href="#verify_outgoing">`verify_outgoing`</a> - If set to
|
||||||
true, Consul requires that all outgoing connections
|
true, Consul requires that all outgoing connections
|
||||||
make use of TLS and that the server provides a certificate that is signed by
|
make use of TLS and that the server provides a certificate that is signed by
|
||||||
the Certificate Authority from the [`ca_file`](#ca_file). By default, this is false, and Consul
|
a Certificate Authority from the [`ca_file`](#ca_file) or [`ca_path`](#ca_path). By default,
|
||||||
will not make use of TLS for outgoing connections. This applies to clients and servers
|
this is false, and Consul will not make use of TLS for outgoing connections. This applies to clients
|
||||||
as both will make outgoing connections.
|
and servers as both will make outgoing connections.
|
||||||
|
|
||||||
* <a name="verify_server_hostname"></a><a href="#verify_server_hostname">`verify_server_hostname`</a> - If set to
|
* <a name="verify_server_hostname"></a><a href="#verify_server_hostname">`verify_server_hostname`</a> - If set to
|
||||||
true, Consul verifies for all outgoing connections that the TLS certificate presented by the servers
|
true, Consul verifies for all outgoing connections that the TLS certificate presented by the servers
|
||||||
|
Loading…
x
Reference in New Issue
Block a user