grpc: send client traffic through envoy (#2469)

* wip

* wip

* handle wildcards in override name

* remove wait for ready, add comment about sync, force initial sync complete in test

* address comments
This commit is contained in:
Caleb Doxsey 2021-08-16 16:12:22 -06:00 committed by GitHub
parent 87c3c675d2
commit bbec2cae9f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 391 additions and 480 deletions

View file

@ -5,7 +5,6 @@ package pomerium
import (
"context"
"fmt"
"net"
"net/http"
"os"
"os/signal"
@ -66,7 +65,7 @@ func Run(ctx context.Context, configFile string) error {
defer traceMgr.Close()
// setup the control plane
controlPlane, err := controlplane.NewServer(src.GetConfig().Options.Services, metricsMgr)
controlPlane, err := controlplane.NewServer(src.GetConfig(), metricsMgr)
if err != nil {
return fmt.Errorf("error creating control plane: %w", err)
}
@ -83,14 +82,14 @@ func Run(ctx context.Context, configFile string) error {
return fmt.Errorf("applying config: %w", err)
}
_, grpcPort, _ := net.SplitHostPort(controlPlane.GRPCListener.Addr().String())
_, httpPort, _ := net.SplitHostPort(controlPlane.HTTPListener.Addr().String())
log.Info(ctx).Str("port", grpcPort).Msg("gRPC server started")
log.Info(ctx).Str("port", httpPort).Msg("HTTP server started")
log.Info(ctx).
Str("grpc-port", src.GetConfig().GRPCPort).
Str("http-port", src.GetConfig().HTTPPort).
Str("outbound-port", src.GetConfig().OutboundPort).
Msg("server started")
// create envoy server
envoyServer, err := envoy.NewServer(ctx, src, grpcPort, httpPort, controlPlane.Builder)
envoyServer, err := envoy.NewServer(ctx, src, controlPlane.Builder)
if err != nil {
return fmt.Errorf("error creating envoy server: %w", err)
}
@ -143,13 +142,6 @@ func Run(ctx context.Context, configFile string) error {
eg.Go(func() error {
return authorizeServer.Run(ctx)
})
// in non-all-in-one mode we will wait for the initial sync to complete before starting
// the control plane
if dataBrokerServer == nil {
if err := authorizeServer.WaitForInitialSync(ctx); err != nil {
return err
}
}
}
eg.Go(func() error {
return controlPlane.Run(ctx)

View file

@ -81,29 +81,18 @@ func (srv *Server) storeEnvoyConfigurationEvent(ctx context.Context, evt *events
}
func (srv *Server) getDataBrokerClient(ctx context.Context) (databrokerpb.DataBrokerServiceClient, error) {
options := srv.currentConfig.Load().Options
cfg := srv.currentConfig.Load()
sharedKey, err := options.GetSharedKey()
sharedKey, err := cfg.Options.GetSharedKey()
if err != nil {
return nil, err
}
urls, err := options.GetDataBrokerURLs()
if err != nil {
return nil, err
}
cc, err := grpc.GetGRPCClientConn(ctx, "databroker", &grpc.Options{
Addrs: urls,
OverrideCertificateName: options.OverrideCertificateName,
CA: options.CA,
CAFile: options.CAFile,
RequestTimeout: options.GRPCClientTimeout,
ClientDNSRoundRobin: options.GRPCClientDNSRoundRobin,
WithInsecure: options.GetGRPCInsecure(),
InstallationID: options.InstallationID,
ServiceName: options.Services,
SignedJWTKey: sharedKey,
cc, err := grpc.GetOutboundGRPCClientConn(context.Background(), &grpc.OutboundOptions{
OutboundPort: cfg.OutboundPort,
InstallationID: cfg.Options.InstallationID,
ServiceName: cfg.Options.Services,
SignedJWTKey: sharedKey,
})
if err != nil {
return nil, fmt.Errorf("controlplane: error creating databroker connection: %w", err)

View file

@ -69,6 +69,7 @@ func TestEvents(t *testing.T) {
li, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err)
defer li.Close()
_, outboundPort, _ := net.SplitHostPort(li.Addr().String())
var putRequest *databrokerpb.PutRequest
var setOptionsRequest *databrokerpb.SetOptionsRequest
@ -100,6 +101,7 @@ func TestEvents(t *testing.T) {
srv := &Server{}
srv.currentConfig.Store(versionedConfig{
Config: &config.Config{
OutboundPort: outboundPort,
Options: &config.Options{
SharedKey: cryptutil.NewBase64Key(),
DataBrokerURLString: "http://" + li.Addr().String(),

View file

@ -68,20 +68,20 @@ type Server struct {
}
// NewServer creates a new Server. Listener ports are chosen by the OS.
func NewServer(name string, metricsMgr *config.MetricsManager) (*Server, error) {
func NewServer(cfg *config.Config, metricsMgr *config.MetricsManager) (*Server, error) {
srv := &Server{
metricsMgr: metricsMgr,
reproxy: reproxy.New(),
envoyConfigurationEvents: make(chan *events.EnvoyConfigurationEvent, 10),
}
srv.currentConfig.Store(versionedConfig{
Config: &config.Config{Options: &config.Options{}},
Config: cfg,
})
var err error
// setup gRPC
srv.GRPCListener, err = net.Listen("tcp4", "127.0.0.1:0")
srv.GRPCListener, err = net.Listen("tcp4", net.JoinHostPort("127.0.0.1", cfg.GRPCPort))
if err != nil {
return nil, err
}
@ -92,7 +92,7 @@ func NewServer(name string, metricsMgr *config.MetricsManager) (*Server, error)
),
)
srv.GRPCServer = grpc.NewServer(
grpc.StatsHandler(telemetry.NewGRPCServerStatsHandler(name)),
grpc.StatsHandler(telemetry.NewGRPCServerStatsHandler(cfg.Options.Services)),
grpc.ChainUnaryInterceptor(requestid.UnaryServerInterceptor(), ui),
grpc.ChainStreamInterceptor(requestid.StreamServerInterceptor(), si),
)
@ -102,7 +102,7 @@ func NewServer(name string, metricsMgr *config.MetricsManager) (*Server, error)
grpc_health_v1.RegisterHealthServer(srv.GRPCServer, pom_grpc.NewHealthCheckServer())
// setup HTTP
srv.HTTPListener, err = net.Listen("tcp4", "127.0.0.1:0")
srv.HTTPListener, err = net.Listen("tcp4", net.JoinHostPort("127.0.0.1", cfg.HTTPPort))
if err != nil {
_ = srv.GRPCListener.Close()
return nil, err
@ -121,7 +121,7 @@ func NewServer(name string, metricsMgr *config.MetricsManager) (*Server, error)
)
ctx := log.WithContext(context.Background(), func(c zerolog.Context) zerolog.Context {
return c.Str("server_name", name)
return c.Str("server_name", cfg.Options.Services)
})
res, err := srv.buildDiscoveryResources(ctx)

View file

@ -157,23 +157,12 @@ func (src *ConfigSource) rebuild(ctx context.Context, firstTime firstTime) {
}
func (src *ConfigSource) runUpdater(cfg *config.Config) {
urls, err := cfg.Options.GetDataBrokerURLs()
if err != nil {
log.Fatal().Err(err).Send()
return
}
sharedKey, _ := cfg.Options.GetSharedKey()
connectionOptions := &grpc.Options{
Addrs: urls,
OverrideCertificateName: cfg.Options.OverrideCertificateName,
CA: cfg.Options.CA,
CAFile: cfg.Options.CAFile,
RequestTimeout: cfg.Options.GRPCClientTimeout,
ClientDNSRoundRobin: cfg.Options.GRPCClientDNSRoundRobin,
WithInsecure: cfg.Options.GetGRPCInsecure(),
ServiceName: cfg.Options.Services,
SignedJWTKey: sharedKey,
connectionOptions := &grpc.OutboundOptions{
OutboundPort: cfg.OutboundPort,
InstallationID: cfg.Options.InstallationID,
ServiceName: cfg.Options.Services,
SignedJWTKey: sharedKey,
}
h, err := hashutil.Hash(connectionOptions)
if err != nil {
@ -193,7 +182,7 @@ func (src *ConfigSource) runUpdater(cfg *config.Config) {
ctx := context.Background()
ctx, src.cancel = context.WithCancel(ctx)
cc, err := grpc.NewGRPCClientConn(ctx, connectionOptions)
cc, err := grpc.GetOutboundGRPCClientConn(ctx, connectionOptions)
if err != nil {
log.Error(ctx).Err(err).Msg("databroker: failed to create gRPC connection to data broker")
return

View file

@ -25,6 +25,7 @@ func TestConfigSource(t *testing.T) {
return
}
defer func() { _ = li.Close() }()
_, outboundPort, _ := net.SplitHostPort(li.Addr().String())
dataBrokerServer := New()
srv := grpc.NewServer()
@ -45,7 +46,8 @@ func TestConfigSource(t *testing.T) {
})
baseSource := config.NewStaticSource(&config.Config{
Options: base,
OutboundPort: outboundPort,
Options: base,
})
src := NewConfigSource(ctx, baseSource, func(_ context.Context, cfg *config.Config) {
cfgs <- cfg
@ -86,6 +88,7 @@ func TestConfigSource(t *testing.T) {
}
baseSource.SetConfig(ctx, &config.Config{
Options: base,
OutboundPort: outboundPort,
Options: base,
})
}

View file

@ -63,7 +63,7 @@ type Server struct {
}
// NewServer creates a new server with traffic routed by envoy.
func NewServer(ctx context.Context, src config.Source, grpcPort, httpPort string, builder *envoyconfig.Builder) (*Server, error) {
func NewServer(ctx context.Context, src config.Source, builder *envoyconfig.Builder) (*Server, error) {
wd := filepath.Join(os.TempDir(), workingDirectoryName)
err := os.MkdirAll(wd, embeddedEnvoyPermissions)
if err != nil {
@ -97,8 +97,8 @@ func NewServer(ctx context.Context, src config.Source, grpcPort, httpPort string
srv := &Server{
wd: wd,
builder: builder,
grpcPort: grpcPort,
httpPort: httpPort,
grpcPort: src.GetConfig().GRPCPort,
httpPort: src.GetConfig().HTTPPort,
envoyPath: envoyPath,
monitorProcessCancel: func() {},

View file

@ -0,0 +1,22 @@
// Package netutil contains various functions that help with networking.
package netutil
import "net"
// AllocatePorts allocates random ports suitable for listening.
func AllocatePorts(count int) ([]string, error) {
var ports []string
for i := 0; i < count; i++ {
li, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
return nil, err
}
_, port, _ := net.SplitHostPort(li.Addr().String())
err = li.Close()
if err != nil {
return nil, err
}
ports = append(ports, port)
}
return ports, nil
}

View file

@ -39,23 +39,11 @@ func (r *Reporter) OnConfigChange(ctx context.Context, cfg *config.Config) {
return
}
urls, err := cfg.Options.GetDataBrokerURLs()
if err != nil {
log.Error(ctx).Err(err).Msg("invalid databroker urls")
return
}
registryConn, err := grpc.GetGRPCClientConn(ctx, "databroker", &grpc.Options{
Addrs: urls,
OverrideCertificateName: cfg.Options.OverrideCertificateName,
CA: cfg.Options.CA,
CAFile: cfg.Options.CAFile,
RequestTimeout: cfg.Options.GRPCClientTimeout,
ClientDNSRoundRobin: cfg.Options.GRPCClientDNSRoundRobin,
WithInsecure: cfg.Options.GetGRPCInsecure(),
InstallationID: cfg.Options.InstallationID,
ServiceName: cfg.Options.Services,
SignedJWTKey: sharedKey,
registryConn, err := grpc.GetOutboundGRPCClientConn(ctx, &grpc.OutboundOptions{
OutboundPort: cfg.OutboundPort,
InstallationID: cfg.Options.InstallationID,
ServiceName: cfg.Options.Services,
SignedJWTKey: sharedKey,
})
if err != nil {
log.Error(ctx).Err(err).Msg("connecting to registry")