Merge pull request #14294 from hashicorp/derekm/split-grpc-ports

Add separate grpc tls port.
This commit is contained in:
Derek Menteer 2022-09-08 16:27:38 -05:00 committed by GitHub
commit 9ff0be6950
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 692 additions and 191 deletions

6
.changelog/14294.txt Normal file
View File

@ -0,0 +1,6 @@
```release-note:breaking-change
config: Add new `ports.grpc_tls` configuration option.
Introduce a new port to better separate TLS config from the existing `ports.grpc` config.
The new `ports.grpc_tls` only supports TLS encrypted communication.
The existing `ports.grpc` currently supports both plain-text and tls communication, but tls support will be removed in a future release.
```

View File

@ -213,7 +213,7 @@ type Agent struct {
// depending on the configuration // depending on the configuration
delegate delegate delegate delegate
// externalGRPCServer is the gRPC server exposed on the dedicated gRPC port (as // externalGRPCServer is the gRPC server exposed on dedicated gRPC ports (as
// opposed to the multiplexed "server" port). // opposed to the multiplexed "server" port).
externalGRPCServer *grpc.Server externalGRPCServer *grpc.Server
@ -384,18 +384,18 @@ type Agent struct {
// New process the desired options and creates a new Agent. // New process the desired options and creates a new Agent.
// This process will // This process will
// * parse the config given the config Flags // - parse the config given the config Flags
// * setup logging // - setup logging
// * using predefined logger given in an option // - using predefined logger given in an option
// OR // OR
// * initialize a new logger from the configuration // - initialize a new logger from the configuration
// including setting up gRPC logging // including setting up gRPC logging
// * initialize telemetry // - initialize telemetry
// * create a TLS Configurator // - create a TLS Configurator
// * build a shared connection pool // - build a shared connection pool
// * create the ServiceManager // - create the ServiceManager
// * setup the NodeID if one isn't provided in the configuration // - setup the NodeID if one isn't provided in the configuration
// * create the AutoConfig object for future use in fully // - create the AutoConfig object for future use in fully
// resolving the configuration // resolving the configuration
func New(bd BaseDeps) (*Agent, error) { func New(bd BaseDeps) (*Agent, error) {
a := Agent{ a := Agent{
@ -539,7 +539,7 @@ func (a *Agent) Start(ctx context.Context) error {
// This needs to happen after the initial auto-config is loaded, because TLS // This needs to happen after the initial auto-config is loaded, because TLS
// can only be configured on the gRPC server at the point of creation. // can only be configured on the gRPC server at the point of creation.
a.buildExternalGRPCServer() a.externalGRPCServer = external.NewServer(a.logger.Named("grpc.external"))
if err := a.startLicenseManager(ctx); err != nil { if err := a.startLicenseManager(ctx); err != nil {
return err return err
@ -702,7 +702,7 @@ func (a *Agent) Start(ctx context.Context) error {
a.apiServers.Start(srv) a.apiServers.Start(srv)
} }
// Start gRPC server. // Start grpc and grpc_tls servers.
if err := a.listenAndServeGRPC(); err != nil { if err := a.listenAndServeGRPC(); err != nil {
return err return err
} }
@ -760,15 +760,10 @@ func (a *Agent) Failed() <-chan struct{} {
return a.apiServers.failed return a.apiServers.failed
} }
func (a *Agent) buildExternalGRPCServer() {
a.externalGRPCServer = external.NewServer(a.logger.Named("grpc.external"), a.tlsConfigurator)
}
func (a *Agent) listenAndServeGRPC() error { func (a *Agent) listenAndServeGRPC() error {
if len(a.config.GRPCAddrs) < 1 { if len(a.config.GRPCAddrs) < 1 && len(a.config.GRPCTLSAddrs) < 1 {
return nil return nil
} }
// TODO(agentless): rather than asserting the concrete type of delegate, we // TODO(agentless): rather than asserting the concrete type of delegate, we
// should add a method to the Delegate interface to build a ConfigSource. // should add a method to the Delegate interface to build a ConfigSource.
var cfg xds.ProxyConfigSource = localproxycfg.NewConfigSource(a.proxyConfig) var cfg xds.ProxyConfigSource = localproxycfg.NewConfigSource(a.proxyConfig)
@ -787,7 +782,6 @@ func (a *Agent) listenAndServeGRPC() error {
}() }()
cfg = catalogCfg cfg = catalogCfg
} }
a.xdsServer = xds.NewServer( a.xdsServer = xds.NewServer(
a.config.NodeName, a.config.NodeName,
a.logger.Named(logging.Envoy), a.logger.Named(logging.Envoy),
@ -800,22 +794,61 @@ func (a *Agent) listenAndServeGRPC() error {
) )
a.xdsServer.Register(a.externalGRPCServer) a.xdsServer.Register(a.externalGRPCServer)
ln, err := a.startListeners(a.config.GRPCAddrs) // Attempt to spawn listeners
if err != nil { var listeners []net.Listener
return err start := func(port_name string, addrs []net.Addr, tlsConf *tls.Config) error {
if len(addrs) < 1 {
return nil
}
ln, err := a.startListeners(addrs)
if err != nil {
return err
}
for i := range ln {
// Wrap with TLS, if provided.
if tlsConf != nil {
ln[i] = tls.NewListener(ln[i], tlsConf)
}
listeners = append(listeners, ln[i])
}
for _, l := range ln {
go func(innerL net.Listener) {
a.logger.Info("Started gRPC listeners",
"port_name", port_name,
"address", innerL.Addr().String(),
"network", innerL.Addr().Network(),
)
err := a.externalGRPCServer.Serve(innerL)
if err != nil {
a.logger.Error("gRPC server failed", "port_name", port_name, "error", err)
}
}(l)
}
return nil
} }
for _, l := range ln { // The original grpc port may spawn in either plain-text or TLS mode (for backwards compatibility).
go func(innerL net.Listener) { // TODO: Simplify this block to only spawn plain-text after 1.14 when deprecated TLS support is removed.
a.logger.Info("Started gRPC server", if a.config.GRPCPort > 0 {
"address", innerL.Addr().String(), // Only allow the grpc port to spawn TLS connections if the other grpc_tls port is NOT defined.
"network", innerL.Addr().Network(), var tlsConf *tls.Config = nil
) if a.config.GRPCTLSPort <= 0 && a.tlsConfigurator.GRPCServerUseTLS() {
err := a.externalGRPCServer.Serve(innerL) a.logger.Warn("deprecated gRPC TLS configuration detected. Consider using `ports.grpc_tls` instead")
if err != nil { tlsConf = a.tlsConfigurator.IncomingGRPCConfig()
a.logger.Error("gRPC server failed", "error", err) }
} if err := start("grpc", a.config.GRPCAddrs, tlsConf); err != nil {
}(l) closeListeners(listeners)
return err
}
}
// Only allow grpc_tls to spawn with a TLS listener.
if a.config.GRPCTLSPort > 0 {
if err := start("grpc_tls", a.config.GRPCTLSAddrs, a.tlsConfigurator.IncomingGRPCConfig()); err != nil {
closeListeners(listeners)
return err
}
} }
return nil return nil
} }
@ -1203,6 +1236,7 @@ func newConsulConfig(runtimeCfg *config.RuntimeConfig, logger hclog.Logger) (*co
cfg.RPCAdvertise = runtimeCfg.RPCAdvertiseAddr cfg.RPCAdvertise = runtimeCfg.RPCAdvertiseAddr
cfg.GRPCPort = runtimeCfg.GRPCPort cfg.GRPCPort = runtimeCfg.GRPCPort
cfg.GRPCTLSPort = runtimeCfg.GRPCTLSPort
cfg.Segment = runtimeCfg.SegmentName cfg.Segment = runtimeCfg.SegmentName
if len(runtimeCfg.Segments) > 0 { if len(runtimeCfg.Segments) > 0 {
@ -1506,7 +1540,9 @@ func (a *Agent) ShutdownAgent() error {
} }
// Stop gRPC // Stop gRPC
a.externalGRPCServer.Stop() if a.externalGRPCServer != nil {
a.externalGRPCServer.Stop()
}
// Stop the proxy config manager // Stop the proxy config manager
if a.proxyConfig != nil { if a.proxyConfig != nil {

View File

@ -45,7 +45,19 @@ type Self struct {
type XDSSelf struct { type XDSSelf struct {
SupportedProxies map[string][]string SupportedProxies map[string][]string
Port int // Port could be used for either TLS or plain-text communication
// up through version 1.14. In order to maintain backwards-compatibility,
// Port will now default to TLS and fallback to the standard port value.
// DEPRECATED: Use Ports field instead
Port int
Ports GRPCPorts
}
// GRPCPorts is used to hold the external GRPC server's port numbers.
type GRPCPorts struct {
// Technically, this port is not always plain-text as of 1.14, but will be in a future release.
Plaintext int
TLS int
} }
func (s *HTTPHandlers) AgentSelf(resp http.ResponseWriter, req *http.Request) (interface{}, error) { func (s *HTTPHandlers) AgentSelf(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
@ -78,7 +90,16 @@ func (s *HTTPHandlers) AgentSelf(resp http.ResponseWriter, req *http.Request) (i
SupportedProxies: map[string][]string{ SupportedProxies: map[string][]string{
"envoy": proxysupport.EnvoyVersions, "envoy": proxysupport.EnvoyVersions,
}, },
Port: s.agent.config.GRPCPort, // Prefer the TLS port. See comment on the XDSSelf struct for details.
Port: s.agent.config.GRPCTLSPort,
Ports: GRPCPorts{
Plaintext: s.agent.config.GRPCPort,
TLS: s.agent.config.GRPCTLSPort,
},
}
// Fallback to standard port if TLS is not enabled.
if s.agent.config.GRPCTLSPort <= 0 {
xds.Port = s.agent.config.GRPCPort
} }
} }

View File

@ -1434,15 +1434,8 @@ func TestAgent_Self(t *testing.T) {
cases := map[string]struct { cases := map[string]struct {
hcl string hcl string
expectXDS bool expectXDS bool
grpcTLS bool
}{ }{
"normal": {
hcl: `
node_meta {
somekey = "somevalue"
}
`,
expectXDS: true,
},
"no grpc": { "no grpc": {
hcl: ` hcl: `
node_meta { node_meta {
@ -1453,13 +1446,35 @@ func TestAgent_Self(t *testing.T) {
} }
`, `,
expectXDS: false, expectXDS: false,
grpcTLS: false,
},
"plaintext grpc": {
hcl: `
node_meta {
somekey = "somevalue"
}
`,
expectXDS: true,
grpcTLS: false,
},
"tls grpc": {
hcl: `
node_meta {
somekey = "somevalue"
}
`,
expectXDS: true,
grpcTLS: true,
}, },
} }
for name, tc := range cases { for name, tc := range cases {
tc := tc tc := tc
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
a := NewTestAgent(t, tc.hcl) a := StartTestAgent(t, TestAgent{
HCL: tc.hcl,
UseGRPCTLS: tc.grpcTLS,
})
defer a.Shutdown() defer a.Shutdown()
testrpc.WaitForTestAgent(t, a.RPC, "dc1") testrpc.WaitForTestAgent(t, a.RPC, "dc1")
@ -1487,6 +1502,13 @@ func TestAgent_Self(t *testing.T) {
map[string][]string{"envoy": proxysupport.EnvoyVersions}, map[string][]string{"envoy": proxysupport.EnvoyVersions},
val.XDS.SupportedProxies, val.XDS.SupportedProxies,
) )
require.Equal(t, a.Config.GRPCTLSPort, val.XDS.Ports.TLS)
require.Equal(t, a.Config.GRPCPort, val.XDS.Ports.Plaintext)
if tc.grpcTLS {
require.Equal(t, a.Config.GRPCTLSPort, val.XDS.Port)
} else {
require.Equal(t, a.Config.GRPCPort, val.XDS.Port)
}
} else { } else {
require.Nil(t, val.XDS, "xds component should be missing when gRPC is disabled") require.Nil(t, val.XDS, "xds component should be missing when gRPC is disabled")

View File

@ -2095,7 +2095,7 @@ func TestAgent_HTTPCheck_EnableAgentTLSForChecks(t *testing.T) {
run := func(t *testing.T, ca string) { run := func(t *testing.T, ca string) {
a := StartTestAgent(t, TestAgent{ a := StartTestAgent(t, TestAgent{
UseTLS: true, UseHTTPS: true,
HCL: ` HCL: `
enable_agent_tls_for_checks = true enable_agent_tls_for_checks = true
@ -3873,7 +3873,7 @@ func TestAgent_reloadWatchesHTTPS(t *testing.T) {
} }
t.Parallel() t.Parallel()
a := TestAgent{UseTLS: true} a := TestAgent{UseHTTPS: true}
if err := a.Start(t); err != nil { if err := a.Start(t); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -5220,7 +5220,7 @@ func TestAgent_AutoEncrypt(t *testing.T) {
server = ` + strconv.Itoa(srv.Config.RPCBindAddr.Port) + ` server = ` + strconv.Itoa(srv.Config.RPCBindAddr.Port) + `
} }
retry_join = ["` + srv.Config.SerfBindAddrLAN.String() + `"]`, retry_join = ["` + srv.Config.SerfBindAddrLAN.String() + `"]`,
UseTLS: true, UseHTTPS: true,
}) })
defer client.Shutdown() defer client.Shutdown()

View File

@ -125,10 +125,10 @@ type LoadResult struct {
// //
// The sources are merged in the following order: // The sources are merged in the following order:
// //
// * default configuration // - default configuration
// * config files in alphabetical order // - config files in alphabetical order
// * command line arguments // - command line arguments
// * overrides // - overrides
// //
// The config sources are merged sequentially and later values overwrite // The config sources are merged sequentially and later values overwrite
// previously set values. Slice values are merged by concatenating the two slices. // previously set values. Slice values are merged by concatenating the two slices.
@ -433,6 +433,7 @@ func (b *builder) build() (rt RuntimeConfig, err error) {
httpsPort := b.portVal("ports.https", c.Ports.HTTPS) httpsPort := b.portVal("ports.https", c.Ports.HTTPS)
serverPort := b.portVal("ports.server", c.Ports.Server) serverPort := b.portVal("ports.server", c.Ports.Server)
grpcPort := b.portVal("ports.grpc", c.Ports.GRPC) grpcPort := b.portVal("ports.grpc", c.Ports.GRPC)
grpcTlsPort := b.portVal("ports.grpc_tls", c.Ports.GRPCTLS)
serfPortLAN := b.portVal("ports.serf_lan", c.Ports.SerfLAN) serfPortLAN := b.portVal("ports.serf_lan", c.Ports.SerfLAN)
serfPortWAN := b.portVal("ports.serf_wan", c.Ports.SerfWAN) serfPortWAN := b.portVal("ports.serf_wan", c.Ports.SerfWAN)
proxyMinPort := b.portVal("ports.proxy_min_port", c.Ports.ProxyMinPort) proxyMinPort := b.portVal("ports.proxy_min_port", c.Ports.ProxyMinPort)
@ -563,6 +564,7 @@ func (b *builder) build() (rt RuntimeConfig, err error) {
httpAddrs := b.makeAddrs(b.expandAddrs("addresses.http", c.Addresses.HTTP), clientAddrs, httpPort) httpAddrs := b.makeAddrs(b.expandAddrs("addresses.http", c.Addresses.HTTP), clientAddrs, httpPort)
httpsAddrs := b.makeAddrs(b.expandAddrs("addresses.https", c.Addresses.HTTPS), clientAddrs, httpsPort) httpsAddrs := b.makeAddrs(b.expandAddrs("addresses.https", c.Addresses.HTTPS), clientAddrs, httpsPort)
grpcAddrs := b.makeAddrs(b.expandAddrs("addresses.grpc", c.Addresses.GRPC), clientAddrs, grpcPort) grpcAddrs := b.makeAddrs(b.expandAddrs("addresses.grpc", c.Addresses.GRPC), clientAddrs, grpcPort)
grpcTlsAddrs := b.makeAddrs(b.expandAddrs("addresses.grpc_tls", c.Addresses.GRPCTLS), clientAddrs, grpcTlsPort)
for _, a := range dnsAddrs { for _, a := range dnsAddrs {
if x, ok := a.(*net.TCPAddr); ok { if x, ok := a.(*net.TCPAddr); ok {
@ -987,8 +989,10 @@ func (b *builder) build() (rt RuntimeConfig, err error) {
EnableRemoteScriptChecks: enableRemoteScriptChecks, EnableRemoteScriptChecks: enableRemoteScriptChecks,
EnableLocalScriptChecks: enableLocalScriptChecks, EnableLocalScriptChecks: enableLocalScriptChecks,
EncryptKey: stringVal(c.EncryptKey), EncryptKey: stringVal(c.EncryptKey),
GRPCPort: grpcPort,
GRPCAddrs: grpcAddrs, GRPCAddrs: grpcAddrs,
GRPCPort: grpcPort,
GRPCTLSAddrs: grpcTlsAddrs,
GRPCTLSPort: grpcTlsPort,
HTTPMaxConnsPerClient: intVal(c.Limits.HTTPMaxConnsPerClient), HTTPMaxConnsPerClient: intVal(c.Limits.HTTPMaxConnsPerClient),
HTTPSHandshakeTimeout: b.durationVal("limits.https_handshake_timeout", c.Limits.HTTPSHandshakeTimeout), HTTPSHandshakeTimeout: b.durationVal("limits.https_handshake_timeout", c.Limits.HTTPSHandshakeTimeout),
KVMaxValueSize: uint64Val(c.Limits.KVMaxValueSize), KVMaxValueSize: uint64Val(c.Limits.KVMaxValueSize),

View File

@ -332,10 +332,11 @@ type Consul struct {
} }
type Addresses struct { type Addresses struct {
DNS *string `mapstructure:"dns"` DNS *string `mapstructure:"dns"`
HTTP *string `mapstructure:"http"` HTTP *string `mapstructure:"http"`
HTTPS *string `mapstructure:"https"` HTTPS *string `mapstructure:"https"`
GRPC *string `mapstructure:"grpc"` GRPC *string `mapstructure:"grpc"`
GRPCTLS *string `mapstructure:"grpc_tls"`
} }
type AdvertiseAddrsConfig struct { type AdvertiseAddrsConfig struct {
@ -694,6 +695,7 @@ type Ports struct {
SerfWAN *int `mapstructure:"serf_wan"` SerfWAN *int `mapstructure:"serf_wan"`
Server *int `mapstructure:"server"` Server *int `mapstructure:"server"`
GRPC *int `mapstructure:"grpc"` GRPC *int `mapstructure:"grpc"`
GRPCTLS *int `mapstructure:"grpc_tls"`
ProxyMinPort *int `mapstructure:"proxy_min_port"` ProxyMinPort *int `mapstructure:"proxy_min_port"`
ProxyMaxPort *int `mapstructure:"proxy_max_port"` ProxyMaxPort *int `mapstructure:"proxy_max_port"`
SidecarMinPort *int `mapstructure:"sidecar_min_port"` SidecarMinPort *int `mapstructure:"sidecar_min_port"`

View File

@ -53,7 +53,8 @@ func AddFlags(fs *flag.FlagSet, f *LoadOpts) {
add(&f.FlagValues.EnableLocalScriptChecks, "enable-local-script-checks", "Enables health check scripts from configuration file.") add(&f.FlagValues.EnableLocalScriptChecks, "enable-local-script-checks", "Enables health check scripts from configuration file.")
add(&f.FlagValues.HTTPConfig.AllowWriteHTTPFrom, "allow-write-http-from", "Only allow write endpoint calls from given network. CIDR format, can be specified multiple times.") add(&f.FlagValues.HTTPConfig.AllowWriteHTTPFrom, "allow-write-http-from", "Only allow write endpoint calls from given network. CIDR format, can be specified multiple times.")
add(&f.FlagValues.EncryptKey, "encrypt", "Provides the gossip encryption key.") add(&f.FlagValues.EncryptKey, "encrypt", "Provides the gossip encryption key.")
add(&f.FlagValues.Ports.GRPC, "grpc-port", "Sets the gRPC API port to listen on (currently needed for Envoy xDS only).") add(&f.FlagValues.Ports.GRPC, "grpc-port", "Sets the gRPC API port to listen on.")
add(&f.FlagValues.Ports.GRPCTLS, "grpc-tls-port", "Sets the gRPC-TLS API port to listen on.")
add(&f.FlagValues.Ports.HTTP, "http-port", "Sets the HTTP API port to listen on.") add(&f.FlagValues.Ports.HTTP, "http-port", "Sets the HTTP API port to listen on.")
add(&f.FlagValues.Ports.HTTPS, "https-port", "Sets the HTTPS API port to listen on.") add(&f.FlagValues.Ports.HTTPS, "https-port", "Sets the HTTPS API port to listen on.")
add(&f.FlagValues.StartJoinAddrsLAN, "join", "Address of an agent to join at start time. Can be specified multiple times.") add(&f.FlagValues.StartJoinAddrsLAN, "join", "Address of an agent to join at start time. Can be specified multiple times.")

View File

@ -670,13 +670,18 @@ type RuntimeConfig struct {
// flag: -encrypt string // flag: -encrypt string
EncryptKey string EncryptKey string
// GRPCPort is the port the gRPC server listens on. Currently this only // GRPCPort is the port the gRPC server listens on. It is disabled by default.
// exposes the xDS and ext_authz APIs for Envoy and it is disabled by default.
// //
// hcl: ports { grpc = int } // hcl: ports { grpc = int }
// flags: -grpc-port int // flags: -grpc-port int
GRPCPort int GRPCPort int
// GRPCTLSPort is the port the gRPC server listens on. It is disabled by default.
//
// hcl: ports { grpc_tls = int }
// flags: -grpc-tls-port int
GRPCTLSPort int
// GRPCAddrs contains the list of TCP addresses and UNIX sockets the gRPC // GRPCAddrs contains the list of TCP addresses and UNIX sockets the gRPC
// server will bind to. If the gRPC endpoint is disabled (ports.grpc <= 0) // server will bind to. If the gRPC endpoint is disabled (ports.grpc <= 0)
// the list is empty. // the list is empty.
@ -692,6 +697,21 @@ type RuntimeConfig struct {
// hcl: client_addr = string addresses { grpc = string } ports { grpc = int } // hcl: client_addr = string addresses { grpc = string } ports { grpc = int }
GRPCAddrs []net.Addr GRPCAddrs []net.Addr
// GRPCTLSAddrs contains the list of TCP addresses and UNIX sockets the gRPC
// server will bind to. If the gRPC endpoint is disabled (ports.grpc <= 0)
// the list is empty.
//
// The addresses are taken from 'addresses.grpc_tls' which should contain a
// space separated list of ip addresses, UNIX socket paths and/or
// go-sockaddr templates. UNIX socket paths must be written as
// 'unix://<full path>', e.g. 'unix:///var/run/consul-grpc.sock'.
//
// If 'addresses.grpc_tls' was not provided the 'client_addr' addresses are
// used.
//
// hcl: client_addr = string addresses { grpc_tls = string } ports { grpc_tls = int }
GRPCTLSAddrs []net.Addr
// HTTPAddrs contains the list of TCP addresses and UNIX sockets the HTTP // HTTPAddrs contains the list of TCP addresses and UNIX sockets the HTTP
// server will bind to. If the HTTP endpoint is disabled (ports.http <= 0) // server will bind to. If the HTTP endpoint is disabled (ports.http <= 0)
// the list is empty. // the list is empty.

View File

@ -6016,6 +6016,8 @@ func TestLoad_FullConfig(t *testing.T) {
GRPCPort: 4881, GRPCPort: 4881,
GRPCAddrs: []net.Addr{tcpAddr("32.31.61.91:4881")}, GRPCAddrs: []net.Addr{tcpAddr("32.31.61.91:4881")},
GRPCTLSPort: 5201,
GRPCTLSAddrs: []net.Addr{tcpAddr("23.14.88.19:5201")},
HTTPAddrs: []net.Addr{tcpAddr("83.39.91.39:7999")}, HTTPAddrs: []net.Addr{tcpAddr("83.39.91.39:7999")},
HTTPBlockEndpoints: []string{"RBvAFcGD", "fWOWFznh"}, HTTPBlockEndpoints: []string{"RBvAFcGD", "fWOWFznh"},
AllowWriteHTTPFrom: []*net.IPNet{cidr("127.0.0.0/8"), cidr("22.33.44.55/32"), cidr("0.0.0.0/0")}, AllowWriteHTTPFrom: []*net.IPNet{cidr("127.0.0.0/8"), cidr("22.33.44.55/32"), cidr("0.0.0.0/0")},

View File

@ -192,6 +192,8 @@
"ExposeMinPort": 0, "ExposeMinPort": 0,
"GRPCAddrs": [], "GRPCAddrs": [],
"GRPCPort": 0, "GRPCPort": 0,
"GRPCTLSAddrs": [],
"GRPCTLSPort": 0,
"GossipLANGossipInterval": "0s", "GossipLANGossipInterval": "0s",
"GossipLANGossipNodes": 0, "GossipLANGossipNodes": 0,
"GossipLANProbeInterval": "0s", "GossipLANProbeInterval": "0s",

View File

@ -44,6 +44,7 @@ addresses = {
http = "83.39.91.39" http = "83.39.91.39"
https = "95.17.17.19" https = "95.17.17.19"
grpc = "32.31.61.91" grpc = "32.31.61.91"
grpc_tls = "23.14.88.19"
} }
advertise_addr = "17.99.29.16" advertise_addr = "17.99.29.16"
advertise_addr_wan = "78.63.37.19" advertise_addr_wan = "78.63.37.19"
@ -320,6 +321,7 @@ ports {
https = 15127 https = 15127
server = 3757 server = 3757
grpc = 4881 grpc = 4881
grpc_tls = 5201
proxy_min_port = 2000 proxy_min_port = 2000
proxy_max_port = 3000 proxy_max_port = 3000
sidecar_min_port = 8888 sidecar_min_port = 8888

View File

@ -44,7 +44,8 @@
"dns": "93.95.95.81", "dns": "93.95.95.81",
"http": "83.39.91.39", "http": "83.39.91.39",
"https": "95.17.17.19", "https": "95.17.17.19",
"grpc": "32.31.61.91" "grpc": "32.31.61.91",
"grpc_tls": "23.14.88.19"
}, },
"advertise_addr": "17.99.29.16", "advertise_addr": "17.99.29.16",
"advertise_addr_wan": "78.63.37.19", "advertise_addr_wan": "78.63.37.19",
@ -320,6 +321,7 @@
"https": 15127, "https": 15127,
"server": 3757, "server": 3757,
"grpc": 4881, "grpc": 4881,
"grpc_tls": 5201,
"sidecar_min_port": 8888, "sidecar_min_port": 8888,
"sidecar_max_port": 9999, "sidecar_max_port": 9999,
"expose_min_port": 1111, "expose_min_port": 1111,

View File

@ -133,6 +133,9 @@ type Config struct {
// GRPCPort is the port the public gRPC server listens on. // GRPCPort is the port the public gRPC server listens on.
GRPCPort int GRPCPort int
// GRPCTLSPort is the port the public gRPC TLS server listens on.
GRPCTLSPort int
// (Enterprise-only) The network segment this agent is part of. // (Enterprise-only) The network segment this agent is part of.
Segment string Segment string

View File

@ -1073,9 +1073,11 @@ func (s *Server) handleAliveMember(member serf.Member, nodeEntMeta *acl.Enterpri
}, },
} }
grpcPortStr := member.Tags["grpc_port"] if parts.ExternalGRPCPort > 0 {
if v, err := strconv.Atoi(grpcPortStr); err == nil && v > 0 { service.Meta["grpc_port"] = strconv.Itoa(parts.ExternalGRPCPort)
service.Meta["grpc_port"] = grpcPortStr }
if parts.ExternalGRPCTLSPort > 0 {
service.Meta["grpc_tls_port"] = strconv.Itoa(parts.ExternalGRPCTLSPort)
} }
// Attempt to join the consul server // Attempt to join the consul server

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"strconv"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -19,6 +20,7 @@ import (
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
tokenStore "github.com/hashicorp/consul/agent/token" tokenStore "github.com/hashicorp/consul/agent/token"
"github.com/hashicorp/consul/api" "github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/sdk/freeport"
"github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil"
"github.com/hashicorp/consul/sdk/testutil/retry" "github.com/hashicorp/consul/sdk/testutil/retry"
"github.com/hashicorp/consul/testrpc" "github.com/hashicorp/consul/testrpc"
@ -355,8 +357,10 @@ func TestLeader_CheckServersMeta(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skip("too slow for testing.Short") t.Skip("too slow for testing.Short")
} }
t.Parallel() t.Parallel()
ports := freeport.GetN(t, 2) // s3 grpc, s3 grpc_tls
dir1, s1 := testServerWithConfig(t, func(c *Config) { dir1, s1 := testServerWithConfig(t, func(c *Config) {
c.PrimaryDatacenter = "dc1" c.PrimaryDatacenter = "dc1"
c.ACLsEnabled = true c.ACLsEnabled = true
@ -383,6 +387,8 @@ func TestLeader_CheckServersMeta(t *testing.T) {
c.ACLInitialManagementToken = "root" c.ACLInitialManagementToken = "root"
c.ACLResolverSettings.ACLDefaultPolicy = "allow" c.ACLResolverSettings.ACLDefaultPolicy = "allow"
c.Bootstrap = false c.Bootstrap = false
c.GRPCPort = ports[0]
c.GRPCTLSPort = ports[1]
}) })
defer os.RemoveAll(dir3) defer os.RemoveAll(dir3)
defer s3.Shutdown() defer s3.Shutdown()
@ -456,6 +462,14 @@ func TestLeader_CheckServersMeta(t *testing.T) {
if newVersion != versionToExpect { if newVersion != versionToExpect {
r.Fatalf("Expected version to be updated to %s, was %s", versionToExpect, newVersion) r.Fatalf("Expected version to be updated to %s, was %s", versionToExpect, newVersion)
} }
grpcPort := service.Meta["grpc_port"]
if grpcPort != strconv.Itoa(ports[0]) {
r.Fatalf("Expected grpc port to be %d, was %s", ports[0], grpcPort)
}
grpcTLSPort := service.Meta["grpc_tls_port"]
if grpcTLSPort != strconv.Itoa(ports[1]) {
r.Fatalf("Expected grpc tls port to be %d, was %s", ports[1], grpcTLSPort)
}
}) })
} }

View File

@ -66,11 +66,19 @@ func (b *PeeringBackend) GetServerAddresses() ([]string, error) {
} }
var addrs []string var addrs []string
for _, node := range nodes { for _, node := range nodes {
grpcPortStr := node.ServiceMeta["grpc_port"] // Prefer the TLS port if it is defined.
if v, err := strconv.Atoi(grpcPortStr); err != nil || v < 1 { grpcPortStr := node.ServiceMeta["grpc_tls_port"]
continue // skip server that isn't exporting public gRPC properly if v, err := strconv.Atoi(grpcPortStr); err == nil && v > 0 {
addrs = append(addrs, node.Address+":"+grpcPortStr)
continue
} }
addrs = append(addrs, node.Address+":"+grpcPortStr) // Fallback to the standard port if TLS is not defined.
grpcPortStr = node.ServiceMeta["grpc_port"]
if v, err := strconv.Atoi(grpcPortStr); err == nil && v > 0 {
addrs = append(addrs, node.Address+":"+grpcPortStr)
continue
}
// Skip node if neither defined.
} }
if len(addrs) == 0 { if len(addrs) == 0 {
return nil, fmt.Errorf("a grpc bind port must be specified in the configuration for all servers") return nil, fmt.Errorf("a grpc bind port must be specified in the configuration for all servers")

View File

@ -253,7 +253,7 @@ type Server struct {
// enable RPC forwarding. // enable RPC forwarding.
externalConnectCAServer *connectca.Server externalConnectCAServer *connectca.Server
// externalGRPCServer is the gRPC server exposed on the dedicated gRPC port, as // externalGRPCServer has a gRPC server exposed on the dedicated gRPC ports, as
// opposed to the multiplexed "server" port which is served by grpcHandler. // opposed to the multiplexed "server" port which is served by grpcHandler.
externalGRPCServer *grpc.Server externalGRPCServer *grpc.Server
@ -377,7 +377,6 @@ type Server struct {
// embedded struct to hold all the enterprise specific data // embedded struct to hold all the enterprise specific data
EnterpriseServer EnterpriseServer
} }
type connHandler interface { type connHandler interface {
Run() error Run() error
Handle(conn net.Conn) Handle(conn net.Conn)

View File

@ -107,6 +107,9 @@ func (s *Server) setupSerfConfig(opts setupSerfOptions) (*serf.Config, error) {
if s.config.GRPCPort > 0 { if s.config.GRPCPort > 0 {
conf.Tags["grpc_port"] = fmt.Sprintf("%d", s.config.GRPCPort) conf.Tags["grpc_port"] = fmt.Sprintf("%d", s.config.GRPCPort)
} }
if s.config.GRPCTLSPort > 0 {
conf.Tags["grpc_tls_port"] = fmt.Sprintf("%d", s.config.GRPCTLSPort)
}
if s.config.Bootstrap { if s.config.Bootstrap {
conf.Tags["bootstrap"] = "1" conf.Tags["bootstrap"] = "1"
} }

View File

@ -1,6 +1,7 @@
package consul package consul
import ( import (
"crypto/tls"
"crypto/x509" "crypto/x509"
"fmt" "fmt"
"net" "net"
@ -218,9 +219,10 @@ func testServerWithConfig(t *testing.T, configOpts ...func(*Config)) (string, *S
var dir string var dir string
var srv *Server var srv *Server
var config *Config
var deps Deps
// Retry added to avoid cases where bind addr is already in use // Retry added to avoid cases where bind addr is already in use
retry.RunWith(retry.ThreeTimes(), t, func(r *retry.R) { retry.RunWith(retry.ThreeTimes(), t, func(r *retry.R) {
var config *Config
dir, config = testServerConfig(t) dir, config = testServerConfig(t)
for _, fn := range configOpts { for _, fn := range configOpts {
fn(config) fn(config)
@ -234,7 +236,8 @@ func testServerWithConfig(t *testing.T, configOpts ...func(*Config)) (string, *S
config.ACLResolverSettings.EnterpriseMeta = *config.AgentEnterpriseMeta() config.ACLResolverSettings.EnterpriseMeta = *config.AgentEnterpriseMeta()
var err error var err error
srv, err = newServer(t, config) deps = newDefaultDeps(t, config)
srv, err = newServerWithDeps(t, config, deps)
if err != nil { if err != nil {
r.Fatalf("err: %v", err) r.Fatalf("err: %v", err)
} }
@ -245,9 +248,14 @@ func testServerWithConfig(t *testing.T, configOpts ...func(*Config)) (string, *S
// Normally the gRPC server listener is created at the agent level and // Normally the gRPC server listener is created at the agent level and
// passed down into the Server creation. // passed down into the Server creation.
externalGRPCAddr := fmt.Sprintf("127.0.0.1:%d", srv.config.GRPCPort) externalGRPCAddr := fmt.Sprintf("127.0.0.1:%d", srv.config.GRPCPort)
ln, err := net.Listen("tcp", externalGRPCAddr) ln, err := net.Listen("tcp", externalGRPCAddr)
require.NoError(t, err) require.NoError(t, err)
// Wrap the listener with TLS
if deps.TLSConfigurator.GRPCServerUseTLS() {
ln = tls.NewListener(ln, deps.TLSConfigurator.IncomingGRPCConfig())
}
go func() { go func() {
_ = srv.externalGRPCServer.Serve(ln) _ = srv.externalGRPCServer.Serve(ln)
}() }()
@ -300,8 +308,8 @@ func newServerWithDeps(t *testing.T, c *Config, deps Deps) (*Server, error) {
oldNotify() oldNotify()
} }
} }
grpcServer := external.NewServer(deps.Logger.Named("grpc.external"))
srv, err := NewServer(c, deps, external.NewServer(deps.Logger.Named("grpc.external"), deps.TLSConfigurator)) srv, err := NewServer(c, deps, grpcServer)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -6,16 +6,14 @@ import (
middleware "github.com/grpc-ecosystem/go-grpc-middleware" middleware "github.com/grpc-ecosystem/go-grpc-middleware"
recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/keepalive" "google.golang.org/grpc/keepalive"
agentmiddleware "github.com/hashicorp/consul/agent/grpc-middleware" agentmiddleware "github.com/hashicorp/consul/agent/grpc-middleware"
"github.com/hashicorp/consul/tlsutil"
) )
// NewServer constructs a gRPC server for the external gRPC port, to which // NewServer constructs a gRPC server for the external gRPC port, to which
// handlers can be registered. // handlers can be registered.
func NewServer(logger agentmiddleware.Logger, tls *tlsutil.Configurator) *grpc.Server { func NewServer(logger agentmiddleware.Logger) *grpc.Server {
recoveryOpts := agentmiddleware.PanicHandlerMiddlewareOpts(logger) recoveryOpts := agentmiddleware.PanicHandlerMiddlewareOpts(logger)
opts := []grpc.ServerOption{ opts := []grpc.ServerOption{
@ -35,9 +33,5 @@ func NewServer(logger agentmiddleware.Logger, tls *tlsutil.Configurator) *grpc.S
MinTime: 15 * time.Second, MinTime: 15 * time.Second,
}), }),
} }
if tls != nil && tls.GRPCServerUseTLS() {
creds := credentials.NewTLS(tls.IncomingGRPCConfig())
opts = append(opts, grpc.Creds(creds))
}
return grpc.NewServer(opts...) return grpc.NewServer(opts...)
} }

View File

@ -148,7 +148,7 @@ func TestSetupHTTPServer_HTTP2(t *testing.T) {
// Fire up an agent with TLS enabled. // Fire up an agent with TLS enabled.
a := StartTestAgent(t, TestAgent{ a := StartTestAgent(t, TestAgent{
UseTLS: true, UseHTTPS: true,
HCL: ` HCL: `
key_file = "../test/client_certs/server.key" key_file = "../test/client_certs/server.key"
cert_file = "../test/client_certs/server.crt" cert_file = "../test/client_certs/server.crt"
@ -1549,7 +1549,7 @@ func TestHTTPServer_HandshakeTimeout(t *testing.T) {
// Fire up an agent with TLS enabled. // Fire up an agent with TLS enabled.
a := StartTestAgent(t, TestAgent{ a := StartTestAgent(t, TestAgent{
UseTLS: true, UseHTTPS: true,
HCL: ` HCL: `
key_file = "../test/client_certs/server.key" key_file = "../test/client_certs/server.key"
cert_file = "../test/client_certs/server.crt" cert_file = "../test/client_certs/server.crt"
@ -1621,7 +1621,7 @@ func TestRPC_HTTPSMaxConnsPerClient(t *testing.T) {
// Fire up an agent with TLS enabled. // Fire up an agent with TLS enabled.
a := StartTestAgent(t, TestAgent{ a := StartTestAgent(t, TestAgent{
UseTLS: tc.tlsEnabled, UseHTTPS: tc.tlsEnabled,
HCL: hclPrefix + ` HCL: hclPrefix + `
limits { limits {
http_max_conns_per_client = 2 http_max_conns_per_client = 2

View File

@ -23,26 +23,27 @@ func (k *Key) Equal(x *Key) bool {
// Server is used to return details of a consul server // Server is used to return details of a consul server
type Server struct { type Server struct {
Name string // <node>.<dc> Name string // <node>.<dc>
ShortName string // <node> ShortName string // <node>
ID string ID string
Datacenter string Datacenter string
Segment string Segment string
Port int Port int
SegmentAddrs map[string]string SegmentAddrs map[string]string
SegmentPorts map[string]int SegmentPorts map[string]int
WanJoinPort int WanJoinPort int
LanJoinPort int LanJoinPort int
ExternalGRPCPort int ExternalGRPCPort int
Bootstrap bool ExternalGRPCTLSPort int
Expect int Bootstrap bool
Build version.Version Expect int
Version int Build version.Version
RaftVersion int Version int
Addr net.Addr RaftVersion int
Status serf.MemberStatus Addr net.Addr
ReadReplica bool Status serf.MemberStatus
FeatureFlags map[string]int ReadReplica bool
FeatureFlags map[string]int
// If true, use TLS when connecting to this server // If true, use TLS when connecting to this server
UseTLS bool UseTLS bool
@ -137,14 +138,18 @@ func IsConsulServer(m serf.Member) (bool, *Server) {
} }
} }
externalGRPCPort := 0 var externalGRPCPort, externalGRPCTLSPort int
externalGRPCPortStr, ok := m.Tags["grpc_port"] externalGRPCPortStr, foundGRPC := m.Tags["grpc_port"]
if ok { externalGRPCTLSPortStr, foundGRPCTLS := m.Tags["grpc_tls_port"]
externalGRPCPort, err = strconv.Atoi(externalGRPCPortStr) if foundGRPC {
if err != nil { externalGRPCPort, _ = strconv.Atoi(externalGRPCPortStr)
return false, nil }
} if foundGRPCTLS {
if externalGRPCPort < 1 { externalGRPCTLSPort, _ = strconv.Atoi(externalGRPCTLSPortStr)
}
// If either port tag was found, check to ensure that at least one port was valid.
if foundGRPC || foundGRPCTLS {
if externalGRPCPort < 1 && externalGRPCTLSPort < 1 {
return false, nil return false, nil
} }
} }
@ -173,25 +178,26 @@ func IsConsulServer(m serf.Member) (bool, *Server) {
addr := &net.TCPAddr{IP: m.Addr, Port: port} addr := &net.TCPAddr{IP: m.Addr, Port: port}
parts := &Server{ parts := &Server{
Name: m.Name, Name: m.Name,
ShortName: strings.TrimSuffix(m.Name, "."+datacenter), ShortName: strings.TrimSuffix(m.Name, "."+datacenter),
ID: m.Tags["id"], ID: m.Tags["id"],
Datacenter: datacenter, Datacenter: datacenter,
Segment: segment, Segment: segment,
Port: port, Port: port,
SegmentAddrs: segmentAddrs, SegmentAddrs: segmentAddrs,
SegmentPorts: segmentPorts, SegmentPorts: segmentPorts,
WanJoinPort: wanJoinPort, WanJoinPort: wanJoinPort,
LanJoinPort: int(m.Port), LanJoinPort: int(m.Port),
ExternalGRPCPort: externalGRPCPort, ExternalGRPCPort: externalGRPCPort,
Bootstrap: bootstrap, ExternalGRPCTLSPort: externalGRPCTLSPort,
Expect: expect, Bootstrap: bootstrap,
Addr: addr, Expect: expect,
Build: *buildVersion, Addr: addr,
Version: vsn, Build: *buildVersion,
RaftVersion: raftVsn, Version: vsn,
Status: m.Status, RaftVersion: raftVsn,
UseTLS: useTLS, Status: m.Status,
UseTLS: useTLS,
// DEPRECATED - remove nonVoter check once support for that tag is removed // DEPRECATED - remove nonVoter check once support for that tag is removed
ReadReplica: nonVoter || readReplica, ReadReplica: nonVoter || readReplica,
FeatureFlags: featureFlags, FeatureFlags: featureFlags,

View File

@ -73,6 +73,7 @@ func TestIsConsulServer(t *testing.T) {
"build": "0.8.0", "build": "0.8.0",
"wan_join_port": "1234", "wan_join_port": "1234",
"grpc_port": "9876", "grpc_port": "9876",
"grpc_tls_port": "9877",
"vsn": "1", "vsn": "1",
"expect": "3", "expect": "3",
"raft_vsn": "3", "raft_vsn": "3",
@ -82,19 +83,20 @@ func TestIsConsulServer(t *testing.T) {
} }
expected := &metadata.Server{ expected := &metadata.Server{
Name: "foo", Name: "foo",
ShortName: "foo", ShortName: "foo",
ID: "asdf", ID: "asdf",
Datacenter: "east-aws", Datacenter: "east-aws",
Segment: "", Segment: "",
Port: 10000, Port: 10000,
SegmentAddrs: map[string]string{}, SegmentAddrs: map[string]string{},
SegmentPorts: map[string]int{}, SegmentPorts: map[string]int{},
WanJoinPort: 1234, WanJoinPort: 1234,
LanJoinPort: 5454, LanJoinPort: 5454,
ExternalGRPCPort: 9876, ExternalGRPCPort: 9876,
Bootstrap: false, ExternalGRPCTLSPort: 9877,
Expect: 3, Bootstrap: false,
Expect: 3,
Addr: &net.TCPAddr{ Addr: &net.TCPAddr{
IP: net.IP([]byte{127, 0, 0, 1}), IP: net.IP([]byte{127, 0, 0, 1}),
Port: 10000, Port: 10000,
@ -137,15 +139,41 @@ func TestIsConsulServer(t *testing.T) {
case "feature-namespaces": case "feature-namespaces":
m.Tags["ft_ns"] = "1" m.Tags["ft_ns"] = "1"
expected.FeatureFlags = map[string]int{"ns": 1} expected.FeatureFlags = map[string]int{"ns": 1}
//
case "bad-grpc-port":
m.Tags["grpc_port"] = "three"
case "negative-grpc-port":
m.Tags["grpc_port"] = "-1"
case "zero-grpc-port":
m.Tags["grpc_port"] = "0"
case "no-role": case "no-role":
delete(m.Tags, "role") delete(m.Tags, "role")
//
case "missing-grpc-port":
delete(m.Tags, "grpc_port")
expected.ExternalGRPCPort = 0
case "missing-grpc-tls-port":
delete(m.Tags, "grpc_tls_port")
expected.ExternalGRPCTLSPort = 0
case "missing-both-grpc-ports":
delete(m.Tags, "grpc_port")
delete(m.Tags, "grpc_tls_port")
expected.ExternalGRPCPort = 0
expected.ExternalGRPCTLSPort = 0
case "bad-both-grpc-ports":
m.Tags["grpc_port"] = ""
m.Tags["grpc_tls_port"] = ""
case "bad-grpc-port":
m.Tags["grpc_port"] = "three"
m.Tags["grpc_tls_port"] = ""
case "bad-grpc-tls-port":
m.Tags["grpc_port"] = ""
m.Tags["grpc_tls_port"] = "three"
case "negative-grpc-port":
m.Tags["grpc_port"] = "-1"
m.Tags["grpc_tls_port"] = ""
case "negative-grpc-tls-port":
m.Tags["grpc_port"] = ""
m.Tags["grpc_tls_port"] = "-1"
case "zero-grpc-port":
m.Tags["grpc_port"] = "0"
m.Tags["grpc_tls_port"] = ""
case "zero-grpc-tls-port":
m.Tags["grpc_port"] = ""
m.Tags["grpc_tls_port"] = "0"
default: default:
t.Fatalf("unhandled variant: %s", variant) t.Fatalf("unhandled variant: %s", variant)
} }
@ -174,11 +202,18 @@ func TestIsConsulServer(t *testing.T) {
"bootstrapped": true, "bootstrapped": true,
"optionals": true, "optionals": true,
"feature-namespaces": true, "feature-namespaces": true,
//
"no-role": false, "no-role": false,
"bad-grpc-port": false, //
"negative-grpc-port": false, "missing-grpc-port": true,
"zero-grpc-port": false, "missing-grpc-tls-port": true,
"missing-both-grpc-ports": true,
"bad-both-grpc-ports": false,
"bad-grpc-port": false,
"negative-grpc-port": false,
"zero-grpc-port": false,
"bad-grpc-tls-port": false,
"negative-grpc-tls-port": false,
"zero-grpc-tls-port": false,
} }
for variant, expectOK := range cases { for variant, expectOK := range cases {

View File

@ -66,9 +66,13 @@ type TestAgent struct {
// and the directory will be removed once the test ends. // and the directory will be removed once the test ends.
DataDir string DataDir string
// UseTLS, if true, will disable the HTTP port and enable the HTTPS // UseHTTPS, if true, will disable the HTTP port and enable the HTTPS
// one. // one.
UseTLS bool UseHTTPS bool
// UseGRPCTLS, if true, will disable the GRPC port and enable the GRPC+TLS
// one.
UseGRPCTLS bool
// dns is a reference to the first started DNS endpoint. // dns is a reference to the first started DNS endpoint.
// It is valid after Start(). // It is valid after Start().
@ -183,7 +187,7 @@ func (a *TestAgent) Start(t *testing.T) error {
Name: name, Name: name,
}) })
portsConfig := randomPortsSource(t, a.UseTLS) portsConfig := randomPortsSource(t, a.UseHTTPS, a.UseGRPCTLS)
// Create NodeID outside the closure, so that it does not change // Create NodeID outside the closure, so that it does not change
testHCLConfig := TestConfigHCL(NodeID()) testHCLConfig := TestConfigHCL(NodeID())
@ -401,11 +405,11 @@ func (a *TestAgent) consulConfig() *consul.Config {
// chance of port conflicts for concurrently executed test binaries. // chance of port conflicts for concurrently executed test binaries.
// Instead of relying on one set of ports to be sufficient we retry // Instead of relying on one set of ports to be sufficient we retry
// starting the agent with different ports on port conflict. // starting the agent with different ports on port conflict.
func randomPortsSource(t *testing.T, tls bool) string { func randomPortsSource(t *testing.T, useHTTPS bool, useGRPCTLS bool) string {
ports := freeport.GetN(t, 7) ports := freeport.GetN(t, 8)
var http, https int var http, https int
if tls { if useHTTPS {
http = -1 http = -1
https = ports[2] https = ports[2]
} else { } else {
@ -413,6 +417,15 @@ func randomPortsSource(t *testing.T, tls bool) string {
https = -1 https = -1
} }
var grpc, grpcTLS int
if useGRPCTLS {
grpc = -1
grpcTLS = ports[7]
} else {
grpc = ports[6]
grpcTLS = -1
}
return ` return `
ports = { ports = {
dns = ` + strconv.Itoa(ports[0]) + ` dns = ` + strconv.Itoa(ports[0]) + `
@ -421,7 +434,8 @@ func randomPortsSource(t *testing.T, tls bool) string {
serf_lan = ` + strconv.Itoa(ports[3]) + ` serf_lan = ` + strconv.Itoa(ports[3]) + `
serf_wan = ` + strconv.Itoa(ports[4]) + ` serf_wan = ` + strconv.Itoa(ports[4]) + `
server = ` + strconv.Itoa(ports[5]) + ` server = ` + strconv.Itoa(ports[5]) + `
grpc = ` + strconv.Itoa(ports[6]) + ` grpc = ` + strconv.Itoa(grpc) + `
grpc_tls = ` + strconv.Itoa(grpcTLS) + `
} }
` `
} }

View File

@ -213,8 +213,8 @@ func (c *cmd) run(args []string) int {
} }
ui.Info(fmt.Sprintf(" Datacenter: '%s' (Segment: '%s')", config.Datacenter, segment)) ui.Info(fmt.Sprintf(" Datacenter: '%s' (Segment: '%s')", config.Datacenter, segment))
ui.Info(fmt.Sprintf(" Server: %v (Bootstrap: %v)", config.ServerMode, config.Bootstrap)) ui.Info(fmt.Sprintf(" Server: %v (Bootstrap: %v)", config.ServerMode, config.Bootstrap))
ui.Info(fmt.Sprintf(" Client Addr: %v (HTTP: %d, HTTPS: %d, gRPC: %d, DNS: %d)", config.ClientAddrs, ui.Info(fmt.Sprintf(" Client Addr: %v (HTTP: %d, HTTPS: %d, gRPC: %d, gRPC-TLS: %d, DNS: %d)", config.ClientAddrs,
config.HTTPPort, config.HTTPSPort, config.GRPCPort, config.DNSPort)) config.HTTPPort, config.HTTPSPort, config.GRPCPort, config.GRPCTLSPort, config.DNSPort))
ui.Info(fmt.Sprintf(" Cluster Addr: %v (LAN: %d, WAN: %d)", config.AdvertiseAddrLAN, ui.Info(fmt.Sprintf(" Cluster Addr: %v (LAN: %d, WAN: %d)", config.AdvertiseAddrLAN,
config.SerfPortLAN, config.SerfPortWAN)) config.SerfPortLAN, config.SerfPortWAN))
ui.Info(fmt.Sprintf("Gossip Encryption: %t", config.EncryptKey != "")) ui.Info(fmt.Sprintf("Gossip Encryption: %t", config.EncryptKey != ""))

View File

@ -639,7 +639,7 @@ func (c *cmd) xdsAddress(httpCfg *api.Config) (GRPC, error) {
addr := c.grpcAddr addr := c.grpcAddr
if addr == "" { if addr == "" {
port, err := c.lookupXDSPort() port, protocol, err := c.lookupXDSPort()
if err != nil { if err != nil {
c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err)) c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
} }
@ -648,7 +648,7 @@ func (c *cmd) xdsAddress(httpCfg *api.Config) (GRPC, error) {
// enabled. // enabled.
port = 8502 port = 8502
} }
addr = fmt.Sprintf("localhost:%v", port) addr = fmt.Sprintf("%vlocalhost:%v", protocol, port)
} }
// TODO: parse addr as a url instead of strings.HasPrefix/TrimPrefix // TODO: parse addr as a url instead of strings.HasPrefix/TrimPrefix
@ -697,39 +697,48 @@ func (c *cmd) xdsAddress(httpCfg *api.Config) (GRPC, error) {
return g, nil return g, nil
} }
func (c *cmd) lookupXDSPort() (int, error) { func (c *cmd) lookupXDSPort() (int, string, error) {
self, err := c.client.Agent().Self() self, err := c.client.Agent().Self()
if err != nil { if err != nil {
return 0, err return 0, "", err
} }
type response struct { type response struct {
XDS struct { XDS struct {
Port int Ports struct {
Plaintext int
TLS int
}
} }
} }
var resp response var resp response
if err := mapstructure.Decode(self, &resp); err == nil && resp.XDS.Port != 0 { if err := mapstructure.Decode(self, &resp); err == nil {
return resp.XDS.Port, nil if resp.XDS.Ports.TLS > 0 {
return resp.XDS.Ports.TLS, "https://", nil
}
if resp.XDS.Ports.Plaintext > 0 {
return resp.XDS.Ports.Plaintext, "http://", nil
}
} }
// Fallback to old API for the case where a new consul CLI is being used with // Fallback to old API for the case where a new consul CLI is being used with
// an older API version. // an older API version.
cfg, ok := self["DebugConfig"] cfg, ok := self["DebugConfig"]
if !ok { if !ok {
return 0, fmt.Errorf("unexpected agent response: no debug config") return 0, "", fmt.Errorf("unexpected agent response: no debug config")
} }
// TODO what does this mean? What did the old API look like? How does this affect compatibility?
port, ok := cfg["GRPCPort"] port, ok := cfg["GRPCPort"]
if !ok { if !ok {
return 0, fmt.Errorf("agent does not have grpc port enabled") return 0, "", fmt.Errorf("agent does not have grpc port enabled")
} }
portN, ok := port.(float64) portN, ok := port.(float64)
if !ok { if !ok {
return 0, fmt.Errorf("invalid grpc port in agent response") return 0, "", fmt.Errorf("invalid grpc port in agent response")
} }
return int(portN), nil return int(portN), "", nil
} }
func (c *cmd) Synopsis() string { func (c *cmd) Synopsis() string {

View File

@ -117,8 +117,8 @@ type generateConfigTestCase struct {
Files map[string]string Files map[string]string
ProxyConfig map[string]interface{} ProxyConfig map[string]interface{}
NamespacesEnabled bool NamespacesEnabled bool
XDSPort int // only used for testing custom-configured grpc port XDSPorts agent.GRPCPorts // only used for testing custom-configured grpc port
AgentSelf110 bool // fake the agent API from versions v1.10 and earlier AgentSelf110 bool // fake the agent API from versions v1.10 and earlier
WantArgs BootstrapTplArgs WantArgs BootstrapTplArgs
WantErr string WantErr string
} }
@ -447,9 +447,9 @@ func TestGenerateConfig(t *testing.T) {
}, },
}, },
{ {
Name: "xds-addr-config", Name: "xds-addr-config",
Flags: []string{"-proxy-id", "test-proxy"}, Flags: []string{"-proxy-id", "test-proxy"},
XDSPort: 9999, XDSPorts: agent.GRPCPorts{Plaintext: 9999, TLS: 0},
WantArgs: BootstrapTplArgs{ WantArgs: BootstrapTplArgs{
ProxyCluster: "test-proxy", ProxyCluster: "test-proxy",
ProxyID: "test-proxy", ProxyID: "test-proxy",
@ -470,10 +470,36 @@ func TestGenerateConfig(t *testing.T) {
PrometheusScrapePath: "/metrics", PrometheusScrapePath: "/metrics",
}, },
}, },
{
Name: "grpc-tls-addr-config",
Flags: []string{"-proxy-id", "test-proxy"},
XDSPorts: agent.GRPCPorts{Plaintext: 9997, TLS: 9998},
AgentSelf110: false,
WantArgs: BootstrapTplArgs{
ProxyCluster: "test-proxy",
ProxyID: "test-proxy",
// We don't know this til after the lookup so it will be empty in the
// initial args call we are testing here.
ProxySourceService: "",
// Should resolve IP, note this might not resolve the same way
// everywhere which might make this test brittle but not sure what else
// to do.
GRPC: GRPC{
AgentAddress: "127.0.0.1",
AgentPort: "9998",
AgentTLS: true,
},
AdminAccessLogPath: "/dev/null",
AdminBindAddress: "127.0.0.1",
AdminBindPort: "19000",
LocalAgentClusterName: xds.LocalAgentClusterName,
PrometheusScrapePath: "/metrics",
},
},
{ {
Name: "deprecated-grpc-addr-config", Name: "deprecated-grpc-addr-config",
Flags: []string{"-proxy-id", "test-proxy"}, Flags: []string{"-proxy-id", "test-proxy"},
XDSPort: 9999, XDSPorts: agent.GRPCPorts{Plaintext: 9999, TLS: 0},
AgentSelf110: true, AgentSelf110: true,
WantArgs: BootstrapTplArgs{ WantArgs: BootstrapTplArgs{
ProxyCluster: "test-proxy", ProxyCluster: "test-proxy",
@ -1138,7 +1164,7 @@ func testMockAgent(tc generateConfigTestCase) http.HandlerFunc {
case strings.Contains(r.URL.Path, "/agent/service"): case strings.Contains(r.URL.Path, "/agent/service"):
testMockAgentProxyConfig(tc.ProxyConfig, tc.NamespacesEnabled)(w, r) testMockAgentProxyConfig(tc.ProxyConfig, tc.NamespacesEnabled)(w, r)
case strings.Contains(r.URL.Path, "/agent/self"): case strings.Contains(r.URL.Path, "/agent/self"):
testMockAgentSelf(tc.XDSPort, tc.AgentSelf110)(w, r) testMockAgentSelf(tc.XDSPorts, tc.AgentSelf110)(w, r)
case strings.Contains(r.URL.Path, "/catalog/node-services"): case strings.Contains(r.URL.Path, "/catalog/node-services"):
testMockCatalogNodeServiceList()(w, r) testMockCatalogNodeServiceList()(w, r)
default: default:
@ -1378,7 +1404,7 @@ func TestEnvoyCommand_canBindInternal(t *testing.T) {
// testMockAgentSelf returns an empty /v1/agent/self response except GRPC // testMockAgentSelf returns an empty /v1/agent/self response except GRPC
// port is filled in to match the given wantXDSPort argument. // port is filled in to match the given wantXDSPort argument.
func testMockAgentSelf(wantXDSPort int, agentSelf110 bool) http.HandlerFunc { func testMockAgentSelf(wantXDSPorts agent.GRPCPorts, agentSelf110 bool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
resp := agent.Self{ resp := agent.Self{
Config: map[string]interface{}{ Config: map[string]interface{}{
@ -1388,10 +1414,17 @@ func testMockAgentSelf(wantXDSPort int, agentSelf110 bool) http.HandlerFunc {
if agentSelf110 { if agentSelf110 {
resp.DebugConfig = map[string]interface{}{ resp.DebugConfig = map[string]interface{}{
"GRPCPort": wantXDSPort, "GRPCPort": wantXDSPorts.Plaintext,
} }
} else { } else {
resp.XDS = &agent.XDSSelf{Port: wantXDSPort} resp.XDS = &agent.XDSSelf{
// The deprecated Port field should default to TLS if it's available.
Port: wantXDSPorts.TLS,
Ports: wantXDSPorts,
}
if wantXDSPorts.TLS <= 0 {
resp.XDS.Port = wantXDSPorts.Plaintext
}
} }
selfJSON, err := json.Marshal(resp) selfJSON, err := json.Marshal(resp)

View File

@ -0,0 +1,223 @@
{
"admin": {
"access_log_path": "/dev/null",
"address": {
"socket_address": {
"address": "127.0.0.1",
"port_value": 19000
}
}
},
"node": {
"cluster": "test",
"id": "test-proxy",
"metadata": {
"namespace": "default",
"partition": "default"
}
},
"layered_runtime": {
"layers": [
{
"name": "base",
"static_layer": {
"re2.max_program_size.error_level": 1048576
}
}
]
},
"static_resources": {
"clusters": [
{
"name": "local_agent",
"ignore_health_on_host_removal": false,
"connect_timeout": "1s",
"type": "STATIC",
"transport_socket": {
"name": "tls",
"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext",
"common_tls_context": {
"validation_context": {
"trusted_ca": {
"inline_string": ""
}
}
}
}
},
"http2_protocol_options": {},
"loadAssignment": {
"clusterName": "local_agent",
"endpoints": [
{
"lbEndpoints": [
{
"endpoint": {
"address": {
"socket_address": {
"address": "127.0.0.1",
"port_value": 9998
}
}
}
}
]
}
]
}
}
]
},
"stats_config": {
"stats_tags": [
{
"regex": "^cluster\\.(?:passthrough~)?((?:([^.]+)~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
"tag_name": "consul.destination.custom_hash"
},
{
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:([^.]+)\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
"tag_name": "consul.destination.service_subset"
},
{
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:[^.]+\\.)?([^.]+)\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
"tag_name": "consul.destination.service"
},
{
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.([^.]+)\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
"tag_name": "consul.destination.namespace"
},
{
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:([^.]+)\\.)?[^.]+\\.internal[^.]*\\.[^.]+\\.consul\\.)",
"tag_name": "consul.destination.partition"
},
{
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?([^.]+)\\.internal[^.]*\\.[^.]+\\.consul\\.)",
"tag_name": "consul.destination.datacenter"
},
{
"regex": "^cluster\\.([^.]+\\.(?:[^.]+\\.)?([^.]+)\\.external\\.[^.]+\\.consul\\.)",
"tag_name": "consul.destination.peer"
},
{
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.([^.]+)\\.[^.]+\\.consul\\.)",
"tag_name": "consul.destination.routing_type"
},
{
"regex": "^cluster\\.(?:passthrough~)?((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.([^.]+)\\.consul\\.)",
"tag_name": "consul.destination.trust_domain"
},
{
"regex": "^cluster\\.(?:passthrough~)?(((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+)\\.[^.]+\\.[^.]+\\.consul\\.)",
"tag_name": "consul.destination.target"
},
{
"regex": "^cluster\\.(?:passthrough~)?(((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+)\\.consul\\.)",
"tag_name": "consul.destination.full_target"
},
{
"regex": "^(?:tcp|http)\\.upstream(?:_peered)?\\.(([^.]+)(?:\\.[^.]+)?(?:\\.[^.]+)?\\.[^.]+\\.)",
"tag_name": "consul.upstream.service"
},
{
"regex": "^(?:tcp|http)\\.upstream\\.([^.]+(?:\\.[^.]+)?(?:\\.[^.]+)?\\.([^.]+)\\.)",
"tag_name": "consul.upstream.datacenter"
},
{
"regex": "^(?:tcp|http)\\.upstream_peered\\.([^.]+(?:\\.[^.]+)?\\.([^.]+)\\.)",
"tag_name": "consul.upstream.peer"
},
{
"regex": "^(?:tcp|http)\\.upstream(?:_peered)?\\.([^.]+(?:\\.([^.]+))?(?:\\.[^.]+)?\\.[^.]+\\.)",
"tag_name": "consul.upstream.namespace"
},
{
"regex": "^(?:tcp|http)\\.upstream\\.([^.]+(?:\\.[^.]+)?(?:\\.([^.]+))?\\.[^.]+\\.)",
"tag_name": "consul.upstream.partition"
},
{
"regex": "^cluster\\.((?:([^.]+)~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
"tag_name": "consul.custom_hash"
},
{
"regex": "^cluster\\.((?:[^.]+~)?(?:([^.]+)\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
"tag_name": "consul.service_subset"
},
{
"regex": "^cluster\\.((?:[^.]+~)?(?:[^.]+\\.)?([^.]+)\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
"tag_name": "consul.service"
},
{
"regex": "^cluster\\.((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.([^.]+)\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+\\.consul\\.)",
"tag_name": "consul.namespace"
},
{
"regex": "^cluster\\.((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?([^.]+)\\.internal[^.]*\\.[^.]+\\.consul\\.)",
"tag_name": "consul.datacenter"
},
{
"regex": "^cluster\\.((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.([^.]+)\\.[^.]+\\.consul\\.)",
"tag_name": "consul.routing_type"
},
{
"regex": "^cluster\\.((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.([^.]+)\\.consul\\.)",
"tag_name": "consul.trust_domain"
},
{
"regex": "^cluster\\.(((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+)\\.[^.]+\\.[^.]+\\.consul\\.)",
"tag_name": "consul.target"
},
{
"regex": "^cluster\\.(((?:[^.]+~)?(?:[^.]+\\.)?[^.]+\\.[^.]+\\.(?:[^.]+\\.)?[^.]+\\.[^.]+\\.[^.]+)\\.consul\\.)",
"tag_name": "consul.full_target"
},
{
"tag_name": "local_cluster",
"fixed_value": "test"
},
{
"tag_name": "consul.source.service",
"fixed_value": "test"
},
{
"tag_name": "consul.source.namespace",
"fixed_value": "default"
},
{
"tag_name": "consul.source.partition",
"fixed_value": "default"
},
{
"tag_name": "consul.source.datacenter",
"fixed_value": "dc1"
}
],
"use_all_default_tags": true
},
"dynamic_resources": {
"lds_config": {
"ads": {},
"resource_api_version": "V3"
},
"cds_config": {
"ads": {},
"resource_api_version": "V3"
},
"ads_config": {
"api_type": "DELTA_GRPC",
"transport_api_version": "V3",
"grpc_services": {
"initial_metadata": [
{
"key": "x-consul-token",
"value": ""
}
],
"envoy_grpc": {
"cluster_name": "local_agent"
}
}
}
}
}

View File

@ -608,6 +608,10 @@ Valid time units are 'ns', 'us' (or 'µs'), 'ms', 's', 'm', 'h'."
automatically with this. This is set to `8502` by default when the agent runs automatically with this. This is set to `8502` by default when the agent runs
in `-dev` mode. Currently gRPC is only used to expose Envoy xDS API to Envoy in `-dev` mode. Currently gRPC is only used to expose Envoy xDS API to Envoy
proxies. proxies.
- `grpc_tls` ((#grpc_tls_port)) - The gRPC API with TLS connections, -1 to disable. Default -1 (disabled).
**We recommend using `8502`** for `grpc_tls` by convention as some tooling will work
automatically with this. Usually only one of the `grpc_tls` or `grpc` ports should be defined.
Currently gRPC is only used to expose Envoy xDS API to Envoy proxies.
- `serf_lan` ((#serf_lan_port)) - The Serf LAN port. Default 8301. TCP - `serf_lan` ((#serf_lan_port)) - The Serf LAN port. Default 8301. TCP
and UDP. Equivalent to the [`-serf-lan-port` command line flag](/docs/agent/config/cli-flags#_serf_lan_port). and UDP. Equivalent to the [`-serf-lan-port` command line flag](/docs/agent/config/cli-flags#_serf_lan_port).
- `serf_wan` ((#serf_wan_port)) - The Serf WAN port. Default 8302. - `serf_wan` ((#serf_wan_port)) - The Serf WAN port. Default 8302.
@ -2003,7 +2007,7 @@ specially crafted certificate signed by the CA can be used to gain full access t
interface. interface.
- `grpc` ((#tls_grpc)) Provides settings for the gRPC/xDS interface. To enable - `grpc` ((#tls_grpc)) Provides settings for the gRPC/xDS interface. To enable
the gRPC interface you must define a port via [`ports.grpc`](#grpc_port). the gRPC interface you must define a port via [`ports.grpc_tls`](#grpc_tls_port).
- `ca_file` ((#tls_grpc_ca_file)) Overrides [`tls.defaults.ca_file`](#tls_defaults_ca_file). - `ca_file` ((#tls_grpc_ca_file)) Overrides [`tls.defaults.ca_file`](#tls_defaults_ca_file).

View File

@ -14,6 +14,32 @@ provided for their upgrades as a result of new features or changed behavior.
This page is used to document those details separately from the standard This page is used to document those details separately from the standard
upgrade flow. upgrade flow.
## Consul 1.14.x
### Service Mesh Compatibility
##### Changes to gRPC TLS configuration
**Configuration changes should be made** if using sidecar proxies or gateways
in conjunction with any of the following:
1. [`ports.https`](/docs/agent/config/config-files#https_port) - Encrypts gRPC in Consul 1.12 and prior
2. [`auto_encrypt`](/docs/agent/config/config-files#auto_encrypt) - Encrypts gRPC in Consul 1.13 and prior
3. [`auto_config`](/docs/agent/config/config-files#auto_config) - Encrypts gRPC in Consul 1.13 and prior
Prior to Consul 1.14, it was possible for communication between Consul and Envoy over `ports.grpc`
to be encrypted by one of these features.
In Consul 1.14, a new [`ports.grpc_tls`](/docs/agent/config/config-files#grpc_tls_port) configuration
is introduced. The existing [`ports.grpc`](/docs/agent/config/config-files#grpc_port) configuration
**will stop supporting encryption in a future release**. Now, the recommended way to encrypt gRPC
traffic is only via `ports.grpc_tls`.
For most environments, the Envoy communication to Consul is loop-back only and does not benefit from encryption.
If you would like to continue utilizing encryption for gRPC, change the existing `ports.grpc` to `ports.grpc_tls` in
your configuration during the upgrade to ensure compatibility with future releases.
## Consul 1.13.x ## Consul 1.13.x
### Service Mesh Compatibility ### Service Mesh Compatibility