Added new auto_encrypt.grpc_server_tls config option to control AutoTLS enabling of GRPC Server's TLS usage
Fix for #14253 Co-authored-by: trujillo-adam <47586768+trujillo-adam@users.noreply.github.com>
This commit is contained in:
parent
bb56a3ee50
commit
4188769c32
|
@ -2531,10 +2531,9 @@ func (b *builder) buildTLSConfig(rt RuntimeConfig, t TLS) (tlsutil.Config, error
|
|||
return c, errors.New("verify_server_hostname is only valid in the tls.internal_rpc stanza")
|
||||
}
|
||||
|
||||
// TLS is only enabled on the gRPC listener if there's an HTTPS port configured
|
||||
// for historic and backwards-compatibility reasons.
|
||||
if rt.HTTPSPort <= 0 && (t.GRPC != TLSProtocolConfig{} && t.GRPCModifiedByDeprecatedConfig == nil) {
|
||||
b.warn("tls.grpc was provided but TLS will NOT be enabled on the gRPC listener without an HTTPS listener configured (e.g. via ports.https)")
|
||||
// And UseAutoCert right now only applies to external gRPC interface.
|
||||
if t.Defaults.UseAutoCert != nil || t.HTTPS.UseAutoCert != nil || t.InternalRPC.UseAutoCert != nil {
|
||||
return c, errors.New("use_auto_cert is only valid in the tls.grpc stanza")
|
||||
}
|
||||
|
||||
defaultTLSMinVersion := b.tlsVersion("tls.defaults.tls_min_version", t.Defaults.TLSMinVersion)
|
||||
|
@ -2591,6 +2590,7 @@ func (b *builder) buildTLSConfig(rt RuntimeConfig, t TLS) (tlsutil.Config, error
|
|||
|
||||
mapCommon("https", t.HTTPS, &c.HTTPS)
|
||||
mapCommon("grpc", t.GRPC, &c.GRPC)
|
||||
c.GRPC.UseAutoCert = boolValWithDefault(t.GRPC.UseAutoCert, false)
|
||||
|
||||
c.ServerName = rt.ServerName
|
||||
c.NodeName = rt.NodeName
|
||||
|
|
|
@ -867,6 +867,7 @@ type TLSProtocolConfig struct {
|
|||
VerifyIncoming *bool `mapstructure:"verify_incoming"`
|
||||
VerifyOutgoing *bool `mapstructure:"verify_outgoing"`
|
||||
VerifyServerHostname *bool `mapstructure:"verify_server_hostname"`
|
||||
UseAutoCert *bool `mapstructure:"use_auto_cert"`
|
||||
}
|
||||
|
||||
type TLS struct {
|
||||
|
|
|
@ -5516,7 +5516,70 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
|
|||
},
|
||||
})
|
||||
run(t, testCase{
|
||||
desc: "tls.grpc without ports.https",
|
||||
desc: "tls.grpc.use_auto_cert defaults to false",
|
||||
args: []string{
|
||||
`-data-dir=` + dataDir,
|
||||
},
|
||||
json: []string{`
|
||||
{
|
||||
"tls": {
|
||||
"grpc": {}
|
||||
}
|
||||
}
|
||||
`},
|
||||
hcl: []string{`
|
||||
tls {
|
||||
grpc {}
|
||||
}
|
||||
`},
|
||||
expected: func(rt *RuntimeConfig) {
|
||||
rt.DataDir = dataDir
|
||||
rt.TLS.Domain = "consul."
|
||||
rt.TLS.NodeName = "thehostname"
|
||||
rt.TLS.GRPC.UseAutoCert = false
|
||||
},
|
||||
})
|
||||
run(t, testCase{
|
||||
desc: "tls.grpc.use_auto_cert defaults to false (II)",
|
||||
args: []string{
|
||||
`-data-dir=` + dataDir,
|
||||
},
|
||||
json: []string{`
|
||||
{
|
||||
"tls": {}
|
||||
}
|
||||
`},
|
||||
hcl: []string{`
|
||||
tls {
|
||||
}
|
||||
`},
|
||||
expected: func(rt *RuntimeConfig) {
|
||||
rt.DataDir = dataDir
|
||||
rt.TLS.Domain = "consul."
|
||||
rt.TLS.NodeName = "thehostname"
|
||||
rt.TLS.GRPC.UseAutoCert = false
|
||||
},
|
||||
})
|
||||
run(t, testCase{
|
||||
desc: "tls.grpc.use_auto_cert defaults to false (III)",
|
||||
args: []string{
|
||||
`-data-dir=` + dataDir,
|
||||
},
|
||||
json: []string{`
|
||||
{
|
||||
}
|
||||
`},
|
||||
hcl: []string{`
|
||||
`},
|
||||
expected: func(rt *RuntimeConfig) {
|
||||
rt.DataDir = dataDir
|
||||
rt.TLS.Domain = "consul."
|
||||
rt.TLS.NodeName = "thehostname"
|
||||
rt.TLS.GRPC.UseAutoCert = false
|
||||
},
|
||||
})
|
||||
run(t, testCase{
|
||||
desc: "tls.grpc.use_auto_cert enabled when true",
|
||||
args: []string{
|
||||
`-data-dir=` + dataDir,
|
||||
},
|
||||
|
@ -5524,7 +5587,7 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
|
|||
{
|
||||
"tls": {
|
||||
"grpc": {
|
||||
"cert_file": "cert-1234"
|
||||
"use_auto_cert": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5532,20 +5595,43 @@ func TestLoad_IntegrationWithFlags(t *testing.T) {
|
|||
hcl: []string{`
|
||||
tls {
|
||||
grpc {
|
||||
cert_file = "cert-1234"
|
||||
use_auto_cert = true
|
||||
}
|
||||
}
|
||||
`},
|
||||
expected: func(rt *RuntimeConfig) {
|
||||
rt.DataDir = dataDir
|
||||
|
||||
rt.TLS.Domain = "consul."
|
||||
rt.TLS.NodeName = "thehostname"
|
||||
|
||||
rt.TLS.GRPC.CertFile = "cert-1234"
|
||||
rt.TLS.GRPC.UseAutoCert = true
|
||||
},
|
||||
expectedWarnings: []string{
|
||||
"tls.grpc was provided but TLS will NOT be enabled on the gRPC listener without an HTTPS listener configured (e.g. via ports.https)",
|
||||
})
|
||||
run(t, testCase{
|
||||
desc: "tls.grpc.use_auto_cert disabled when false",
|
||||
args: []string{
|
||||
`-data-dir=` + dataDir,
|
||||
},
|
||||
json: []string{`
|
||||
{
|
||||
"tls": {
|
||||
"grpc": {
|
||||
"use_auto_cert": false
|
||||
}
|
||||
}
|
||||
}
|
||||
`},
|
||||
hcl: []string{`
|
||||
tls {
|
||||
grpc {
|
||||
use_auto_cert = false
|
||||
}
|
||||
}
|
||||
`},
|
||||
expected: func(rt *RuntimeConfig) {
|
||||
rt.DataDir = dataDir
|
||||
rt.TLS.Domain = "consul."
|
||||
rt.TLS.NodeName = "thehostname"
|
||||
rt.TLS.GRPC.UseAutoCert = false
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -6340,6 +6426,7 @@ func TestLoad_FullConfig(t *testing.T) {
|
|||
TLSMinVersion: types.TLSv1_0,
|
||||
CipherSuites: []types.TLSCipherSuite{types.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, types.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
|
||||
VerifyOutgoing: false,
|
||||
UseAutoCert: true,
|
||||
},
|
||||
HTTPS: tlsutil.ProtocolConfig{
|
||||
VerifyIncoming: true,
|
||||
|
|
|
@ -374,7 +374,8 @@
|
|||
"TLSMinVersion": "",
|
||||
"VerifyIncoming": false,
|
||||
"VerifyOutgoing": false,
|
||||
"VerifyServerHostname": false
|
||||
"VerifyServerHostname": false,
|
||||
"UseAutoCert": false
|
||||
},
|
||||
"HTTPS": {
|
||||
"CAFile": "",
|
||||
|
@ -385,7 +386,8 @@
|
|||
"TLSMinVersion": "",
|
||||
"VerifyIncoming": false,
|
||||
"VerifyOutgoing": false,
|
||||
"VerifyServerHostname": false
|
||||
"VerifyServerHostname": false,
|
||||
"UseAutoCert": false
|
||||
},
|
||||
"InternalRPC": {
|
||||
"CAFile": "",
|
||||
|
@ -396,7 +398,8 @@
|
|||
"TLSMinVersion": "",
|
||||
"VerifyIncoming": false,
|
||||
"VerifyOutgoing": false,
|
||||
"VerifyServerHostname": false
|
||||
"VerifyServerHostname": false,
|
||||
"UseAutoCert": false
|
||||
},
|
||||
"NodeName": "",
|
||||
"ServerName": ""
|
||||
|
@ -466,4 +469,4 @@
|
|||
"VersionMetadata": "",
|
||||
"VersionPrerelease": "",
|
||||
"Watches": []
|
||||
}
|
||||
}
|
||||
|
|
|
@ -697,6 +697,7 @@ tls {
|
|||
tls_cipher_suites = "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"
|
||||
tls_min_version = "TLSv1_0"
|
||||
verify_incoming = true
|
||||
use_auto_cert = true
|
||||
}
|
||||
}
|
||||
tls_cipher_suites = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
|
||||
|
|
|
@ -692,7 +692,8 @@
|
|||
"key_file": "1y4prKjl",
|
||||
"tls_cipher_suites": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"tls_min_version": "TLSv1_0",
|
||||
"verify_incoming": true
|
||||
"verify_incoming": true,
|
||||
"use_auto_cert": true
|
||||
}
|
||||
},
|
||||
"tls_cipher_suites": "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package external
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
"time"
|
||||
|
||||
agentmiddleware "github.com/hashicorp/consul/agent/grpc-middleware"
|
||||
"github.com/hashicorp/consul/tlsutil"
|
||||
|
@ -34,7 +35,7 @@ func NewServer(logger agentmiddleware.Logger, tls *tlsutil.Configurator) *grpc.S
|
|||
MinTime: 15 * time.Second,
|
||||
}),
|
||||
}
|
||||
if tls != nil && tls.GRPCTLSConfigured() {
|
||||
if tls != nil && tls.GRPCServerUseTLS() {
|
||||
creds := credentials.NewTLS(tls.IncomingGRPCConfig())
|
||||
opts = append(opts, grpc.Creds(creds))
|
||||
}
|
||||
|
|
|
@ -102,6 +102,10 @@ type ProtocolConfig struct {
|
|||
//
|
||||
// Note: this setting only applies to the Internal RPC configuration.
|
||||
VerifyServerHostname bool
|
||||
|
||||
// UseAutoCert is used to enable usage of auto_encrypt/auto_config generated
|
||||
// certificate & key material on external gRPC listener.
|
||||
UseAutoCert bool
|
||||
}
|
||||
|
||||
// Config configures the Configurator.
|
||||
|
@ -167,6 +171,10 @@ type protocolConfig struct {
|
|||
// combinedCAPool is a pool containing both manualCAPEMs and the certificates
|
||||
// received from auto-config/auto-encrypt.
|
||||
combinedCAPool *x509.CertPool
|
||||
|
||||
// useAutoCert indicates wether we should use auto-encrypt/config data
|
||||
// for TLS server/listener. NOTE: Only applies to external GRPC Server.
|
||||
useAutoCert bool
|
||||
}
|
||||
|
||||
// Configurator provides tls.Config and net.Dial wrappers to enable TLS for
|
||||
|
@ -323,6 +331,7 @@ func (c *Configurator) loadProtocolConfig(base Config, pc ProtocolConfig) (*prot
|
|||
manualCAPEMs: pems,
|
||||
manualCAPool: manualPool,
|
||||
combinedCAPool: combinedPool,
|
||||
useAutoCert: pc.UseAutoCert,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -620,16 +629,15 @@ func (c *Configurator) Cert() *tls.Certificate {
|
|||
return cert
|
||||
}
|
||||
|
||||
// GRPCTLSConfigured returns whether there's a TLS certificate configured for
|
||||
// gRPC (either manually or by auto-config/auto-encrypt). It is checked, along
|
||||
// with the presence of an HTTPS port, to determine whether to enable TLS on
|
||||
// incoming gRPC connections.
|
||||
// GRPCServerUseTLS returns whether there's a TLS certificate configured for
|
||||
// (external) gRPC (either manually or by auto-config/auto-encrypt), and use
|
||||
// of TLS for gRPC has not been explicitly disabled at auto-encrypt.
|
||||
//
|
||||
// This function acquires a read lock because it reads from the config.
|
||||
func (c *Configurator) GRPCTLSConfigured() bool {
|
||||
func (c *Configurator) GRPCServerUseTLS() bool {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
return c.grpc.cert != nil || c.autoTLS.cert != nil
|
||||
return c.grpc.cert != nil || (c.grpc.useAutoCert && c.autoTLS.cert != nil)
|
||||
}
|
||||
|
||||
// VerifyIncomingRPC returns true if we should verify incoming connnections to
|
||||
|
|
|
@ -1465,7 +1465,7 @@ func TestConfigurator_AuthorizeInternalRPCServerConn(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestConfigurator_GRPCTLSConfigured(t *testing.T) {
|
||||
func TestConfigurator_GRPCServerUseTLS(t *testing.T) {
|
||||
t.Run("certificate manually configured", func(t *testing.T) {
|
||||
c := makeConfigurator(t, Config{
|
||||
GRPC: ProtocolConfig{
|
||||
|
@ -1473,22 +1473,47 @@ func TestConfigurator_GRPCTLSConfigured(t *testing.T) {
|
|||
KeyFile: "../test/hostname/Alice.key",
|
||||
},
|
||||
})
|
||||
require.True(t, c.GRPCTLSConfigured())
|
||||
require.True(t, c.GRPCServerUseTLS())
|
||||
})
|
||||
|
||||
t.Run("AutoTLS", func(t *testing.T) {
|
||||
t.Run("no certificate", func(t *testing.T) {
|
||||
c := makeConfigurator(t, Config{})
|
||||
require.False(t, c.GRPCServerUseTLS())
|
||||
})
|
||||
|
||||
t.Run("AutoTLS (default)", func(t *testing.T) {
|
||||
c := makeConfigurator(t, Config{})
|
||||
|
||||
bobCert := loadFile(t, "../test/hostname/Bob.crt")
|
||||
bobKey := loadFile(t, "../test/hostname/Bob.key")
|
||||
require.NoError(t, c.UpdateAutoTLSCert(bobCert, bobKey))
|
||||
|
||||
require.True(t, c.GRPCTLSConfigured())
|
||||
require.False(t, c.GRPCServerUseTLS())
|
||||
})
|
||||
|
||||
t.Run("no certificate", func(t *testing.T) {
|
||||
c := makeConfigurator(t, Config{})
|
||||
require.False(t, c.GRPCTLSConfigured())
|
||||
t.Run("AutoTLS w/ UseAutoCert Disabled", func(t *testing.T) {
|
||||
c := makeConfigurator(t, Config{
|
||||
GRPC: ProtocolConfig{
|
||||
UseAutoCert: false,
|
||||
},
|
||||
})
|
||||
|
||||
bobCert := loadFile(t, "../test/hostname/Bob.crt")
|
||||
bobKey := loadFile(t, "../test/hostname/Bob.key")
|
||||
require.NoError(t, c.UpdateAutoTLSCert(bobCert, bobKey))
|
||||
require.False(t, c.GRPCServerUseTLS())
|
||||
})
|
||||
|
||||
t.Run("AutoTLS w/ UseAutoCert Enabled", func(t *testing.T) {
|
||||
c := makeConfigurator(t, Config{
|
||||
GRPC: ProtocolConfig{
|
||||
UseAutoCert: true,
|
||||
},
|
||||
})
|
||||
|
||||
bobCert := loadFile(t, "../test/hostname/Bob.crt")
|
||||
bobKey := loadFile(t, "../test/hostname/Bob.key")
|
||||
require.NoError(t, c.UpdateAutoTLSCert(bobCert, bobKey))
|
||||
require.True(t, c.GRPCServerUseTLS())
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -2019,6 +2019,8 @@ specially crafted certificate signed by the CA can be used to gain full access t
|
|||
|
||||
- `verify_incoming` - ((#tls_grpc_verify_incoming)) Overrides [`tls.defaults.verify_incoming`](#tls_defaults_verify_incoming).
|
||||
|
||||
- `use_auto_cert` - (Defaults to `false`) Enables or disables TLS on gRPC servers. Set to `true` to allow `auto_encrypt` TLS settings to apply to gRPC listeners. We recommend disabling TLS on gRPC servers if you are using `auto_encrypt` for other TLS purposes, such as enabling HTTPS.
|
||||
|
||||
- `https` ((#tls_https)) Provides settings for the HTTPS interface. To enable
|
||||
the HTTPS interface you must define a port via [`ports.https`](#https_port).
|
||||
|
||||
|
|
Loading…
Reference in New Issue