agent: setup grpc server with auto_encrypt certs and add -https-port (#7086)

* setup grpc server with TLS config used across consul.
* add -https-port flag
This commit is contained in:
Hans Hasselberg 2020-01-22 11:32:17 +01:00 committed by GitHub
parent 82c556d1be
commit 11a571de95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 50 additions and 14 deletions

View File

@ -723,9 +723,9 @@ func (a *Agent) listenAndServeGRPC() error {
if a.config.HTTPSPort > 0 {
// gRPC uses the same TLS settings as the HTTPS API. If HTTPS is
// enabled then gRPC will require HTTPS as well.
a.grpcServer, err = a.xdsServer.GRPCServer(a.config.CertFile, a.config.KeyFile)
a.grpcServer, err = a.xdsServer.GRPCServer(a.tlsConfigurator)
} else {
a.grpcServer, err = a.xdsServer.GRPCServer("", "")
a.grpcServer, err = a.xdsServer.GRPCServer(nil)
}
if err != nil {
return err

View File

@ -79,6 +79,7 @@ func AddFlags(fs *flag.FlagSet, f *Flags) {
add(&f.Config.EncryptKey, "encrypt", "Provides the gossip encryption key.")
add(&f.Config.Ports.GRPC, "grpc-port", "Sets the gRPC API port to listen on (currently needed for Envoy xDS only).")
add(&f.Config.Ports.HTTP, "http-port", "Sets the HTTP API port to listen on.")
add(&f.Config.Ports.HTTPS, "https-port", "Sets the HTTPS API port to listen on.")
add(&f.Config.StartJoinAddrsLAN, "join", "Address of an agent to join at start time. Can be specified multiple times.")
add(&f.Config.StartJoinAddrsWAN, "join-wan", "Address of an agent to join -wan at start time. Can be specified multiple times.")
add(&f.Config.LogLevel, "log-level", "Log level of the agent.")

View File

@ -52,6 +52,14 @@ func TestParseFlags(t *testing.T) {
args: []string{`-grpc-port`, `1`},
flags: Flags{Config: Config{Ports: Ports{GRPC: pInt(1)}}},
},
{
args: []string{`-http-port`, `1`},
flags: Flags{Config: Config{Ports: Ports{HTTP: pInt(1)}}},
},
{
args: []string{`-https-port`, `1`},
flags: Flags{Config: Config{Ports: Ports{HTTPS: pInt(1)}}},
},
{
args: []string{`-serf-lan-port`, `1`},
flags: Flags{Config: Config{Ports: Ports{SerfLAN: pInt(1)}}},

View File

@ -807,6 +807,7 @@ type RuntimeConfig struct {
// Setting this to a value <= 0 disables the endpoint.
//
// hcl: ports { https = int }
// flags: -https-port int
HTTPSPort int
// KeyFile is used to provide a TLS key that is used for serving TLS

View File

@ -25,6 +25,7 @@ import (
"github.com/hashicorp/consul/agent/connect"
"github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/tlsutil"
)
// ADSStream is a shorter way of referring to this thing...
@ -536,16 +537,15 @@ func (s *Server) Check(ctx context.Context, r *envoyauthz.CheckRequest) (*envoya
// GRPCServer returns a server instance that can handle XDS and ext_authz
// requests.
func (s *Server) GRPCServer(certFile, keyFile string) (*grpc.Server, error) {
func (s *Server) GRPCServer(tlsConfigurator *tlsutil.Configurator) (*grpc.Server, error) {
opts := []grpc.ServerOption{
grpc.MaxConcurrentStreams(2048),
}
if certFile != "" && keyFile != "" {
creds, err := credentials.NewServerTLSFromFile(certFile, keyFile)
if err != nil {
return nil, err
if tlsConfigurator != nil {
if tlsConfigurator.Cert() != nil {
creds := credentials.NewTLS(tlsConfigurator.IncomingGRPCConfig())
opts = append(opts, grpc.Creds(creds))
}
opts = append(opts, grpc.Creds(creds))
}
srv := grpc.NewServer(opts...)
envoydisco.RegisterAggregatedDiscoveryServiceServer(srv, s)

View File

@ -441,12 +441,7 @@ func (c *Configurator) commonTLSConfig(verifyIncoming bool) *tls.Config {
// autoEncrypt cert too so that a client can encrypt incoming
// connections without having a manual cert configured.
tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
cert := c.manual.cert
if cert == nil {
cert = c.autoEncrypt.cert
}
return cert, nil
return c.Cert(), nil
}
// GetClientCertificate is used when acting as a client and responding
@ -477,6 +472,17 @@ func (c *Configurator) commonTLSConfig(verifyIncoming bool) *tls.Config {
return tlsConfig
}
// This function acquires a read lock because it reads from the config.
func (c *Configurator) Cert() *tls.Certificate {
c.RLock()
defer c.RUnlock()
cert := c.manual.cert
if cert == nil {
cert = c.autoEncrypt.cert
}
return cert
}
// This function acquires a read lock because it reads from the config.
func (c *Configurator) VerifyIncomingRPC() bool {
c.RLock()
@ -561,6 +567,22 @@ func (c *Configurator) VerifyServerHostname() bool {
return c.base.VerifyServerHostname || c.autoEncrypt.verifyServerHostname
}
// IncomingGRPCConfig generates a *tls.Config for incoming GRPC connections.
func (c *Configurator) IncomingGRPCConfig() *tls.Config {
c.log("IncomingGRPCConfig")
// false has the effect that this config doesn't require a client cert
// verification. This is because there is no verify_incoming_grpc
// configuration option. And using verify_incoming would be backwards
// incompatible, because even if it was set before, it didn't have an
// effect on the grpc server.
config := c.commonTLSConfig(false)
config.GetConfigForClient = func(*tls.ClientHelloInfo) (*tls.Config, error) {
return c.IncomingGRPCConfig(), nil
}
return config
}
// IncomingRPCConfig generates a *tls.Config for incoming RPC connections.
func (c *Configurator) IncomingRPCConfig() *tls.Config {
c.log("IncomingRPCConfig")

View File

@ -277,6 +277,10 @@ The options below are all specified on the command-line.
to an environment which communicates the HTTP port through the environment e.g. PaaS like CloudFoundry, allowing
you to set the port directly via a Procfile.
* <a name="_https_port"></a><a href="#_https_port">`-https-port`</a> - the HTTPS API
port to listen on. Default -1 (https disabled). See [ports](#ports)
documentation for more detail.
* <a name="_log_file"></a><a href="#_log_file">`-log-file`</a> - to redirect all the Consul agent log messages to a file. This can be specified with the complete path along with the name of the log. In case the path doesn't have the filename, the filename defaults to `consul-{timestamp}.log`. Can be combined with <a href="#_log_rotate_bytes"> -log-rotate-bytes</a> and <a href="#_log_rotate_duration"> -log-rotate-duration </a> for a fine-grained log rotation experience.
* <a name="_log_rotate_bytes"></a><a href="#_log_rotate_bytes">`-log-rotate-bytes`</a> - to specify the number of bytes that should be written to a log before it needs to be rotated. Unless specified, there is no limit to the number of bytes that can be written to a log file.