From d23a110e6eaca60c086c8cf61418de7c81ea8945 Mon Sep 17 00:00:00 2001 From: Caleb Doxsey Date: Tue, 4 Apr 2023 13:45:19 -0600 Subject: [PATCH] support loading route configuration via rds --- config/envoyconfig/listeners.go | 72 ++------------ config/envoyconfig/route_configurations.go | 105 +++++++++++++++++++++ internal/controlplane/xds.go | 18 +++- 3 files changed, 131 insertions(+), 64 deletions(-) create mode 100644 config/envoyconfig/route_configurations.go diff --git a/config/envoyconfig/listeners.go b/config/envoyconfig/listeners.go index 8bd935677..eec1061ab 100644 --- a/config/envoyconfig/listeners.go +++ b/config/envoyconfig/listeners.go @@ -257,61 +257,6 @@ func (b *Builder) buildMainHTTPConnectionManagerFilter( options *config.Options, certs ...tls.Certificate, ) (*envoy_config_listener_v3.Filter, error) { - authorizeURLs, err := options.GetInternalAuthorizeURLs() - if err != nil { - return nil, err - } - - dataBrokerURLs, err := options.GetInternalDataBrokerURLs() - if err != nil { - return nil, err - } - - allHosts, err := getAllRouteableHosts(options, options.Addr) - if err != nil { - return nil, err - } - - var virtualHosts []*envoy_config_route_v3.VirtualHost - for _, host := range allHosts { - requireStrictTransportSecurity := cryptutil.HasCertificateForServerName(certs, host) - vh, err := b.buildVirtualHost(options, host, host, requireStrictTransportSecurity) - if err != nil { - return nil, err - } - - if options.Addr == options.GetGRPCAddr() { - // if this is a gRPC service domain and we're supposed to handle that, add those routes - if (config.IsAuthorize(options.Services) && urlsMatchHost(authorizeURLs, host)) || - (config.IsDataBroker(options.Services) && urlsMatchHost(dataBrokerURLs, host)) { - rs, err := b.buildGRPCRoutes() - if err != nil { - return nil, err - } - vh.Routes = append(vh.Routes, rs...) - } - } - - // if we're the proxy, add all the policy routes - if config.IsProxy(options.Services) { - rs, err := b.buildPolicyRoutes(options, host) - if err != nil { - return nil, err - } - vh.Routes = append(vh.Routes, rs...) - } - - if len(vh.Routes) > 0 { - virtualHosts = append(virtualHosts, vh) - } - } - - vh, err := b.buildVirtualHost(options, "catch-all", "*", false) - if err != nil { - return nil, err - } - virtualHosts = append(virtualHosts, vh) - var grpcClientTimeout *durationpb.Duration if options.GRPCClientTimeout != 0 { grpcClientTimeout = durationpb.New(options.GRPCClientTimeout) @@ -333,10 +278,6 @@ func (b *Builder) buildMainHTTPConnectionManagerFilter( maxStreamDuration = durationpb.New(options.WriteTimeout) } - rc, err := b.buildRouteConfiguration("main", virtualHosts) - if err != nil { - return nil, err - } tracingProvider, err := buildTracingHTTP(options) if err != nil { return nil, err @@ -347,8 +288,14 @@ func (b *Builder) buildMainHTTPConnectionManagerFilter( CodecType: options.GetCodecType().ToEnvoy(), StatPrefix: "ingress", - RouteSpecifier: &envoy_http_connection_manager.HttpConnectionManager_RouteConfig{ - RouteConfig: rc, + RouteSpecifier: &envoy_http_connection_manager.HttpConnectionManager_Rds{ + Rds: &envoy_http_connection_manager.Rds{ + ConfigSource: &envoy_config_core_v3.ConfigSource{ + ResourceApiVersion: envoy_config_core_v3.ApiVersion_V3, + ConfigSourceSpecifier: &envoy_config_core_v3.ConfigSource_Ads{}, + }, + RouteConfigName: "main", + }, }, HttpFilters: filters, AccessLog: buildAccessLogs(options), @@ -546,7 +493,8 @@ func (b *Builder) buildDownstreamTLSContextMulti( TlsCertificates: envoyCerts, AlpnProtocols: getALPNProtos(cfg.Options), ValidationContextType: b.buildDownstreamValidationContext(ctx, cfg), - }}, nil + }, + }, nil } func getALPNProtos(opts *config.Options) []string { diff --git a/config/envoyconfig/route_configurations.go b/config/envoyconfig/route_configurations.go new file mode 100644 index 000000000..0ab37eef3 --- /dev/null +++ b/config/envoyconfig/route_configurations.go @@ -0,0 +1,105 @@ +package envoyconfig + +import ( + "context" + "crypto/tls" + + envoy_config_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" + + "github.com/pomerium/pomerium/config" + "github.com/pomerium/pomerium/pkg/cryptutil" +) + +// BuildRouteConfigurations builds the route configurations for the RDS service. +func (b *Builder) BuildRouteConfigurations( + ctx context.Context, + cfg *config.Config, +) ([]*envoy_config_route_v3.RouteConfiguration, error) { + var routeConfigurations []*envoy_config_route_v3.RouteConfiguration + + if config.IsAuthenticate(cfg.Options.Services) || config.IsProxy(cfg.Options.Services) { + rc, err := b.buildMainRouteConfiguration(ctx, cfg) + if err != nil { + return nil, err + } + routeConfigurations = append(routeConfigurations, rc) + } + + return routeConfigurations, nil +} + +func (b *Builder) buildMainRouteConfiguration( + ctx context.Context, + cfg *config.Config, +) (*envoy_config_route_v3.RouteConfiguration, error) { + var certs []tls.Certificate + if !cfg.Options.InsecureServer { + var err error + certs, err = getAllCertificates(cfg) + if err != nil { + return nil, err + } + } + + authorizeURLs, err := cfg.Options.GetInternalAuthorizeURLs() + if err != nil { + return nil, err + } + + dataBrokerURLs, err := cfg.Options.GetInternalDataBrokerURLs() + if err != nil { + return nil, err + } + + allHosts, err := getAllRouteableHosts(cfg.Options, cfg.Options.Addr) + if err != nil { + return nil, err + } + + var virtualHosts []*envoy_config_route_v3.VirtualHost + for _, host := range allHosts { + requireStrictTransportSecurity := cryptutil.HasCertificateForServerName(certs, host) + vh, err := b.buildVirtualHost(cfg.Options, host, host, requireStrictTransportSecurity) + if err != nil { + return nil, err + } + + if cfg.Options.Addr == cfg.Options.GetGRPCAddr() { + // if this is a gRPC service domain and we're supposed to handle that, add those routes + if (config.IsAuthorize(cfg.Options.Services) && urlsMatchHost(authorizeURLs, host)) || + (config.IsDataBroker(cfg.Options.Services) && urlsMatchHost(dataBrokerURLs, host)) { + rs, err := b.buildGRPCRoutes() + if err != nil { + return nil, err + } + vh.Routes = append(vh.Routes, rs...) + } + } + + // if we're the proxy, add all the policy routes + if config.IsProxy(cfg.Options.Services) { + rs, err := b.buildPolicyRoutes(cfg.Options, host) + if err != nil { + return nil, err + } + vh.Routes = append(vh.Routes, rs...) + } + + if len(vh.Routes) > 0 { + virtualHosts = append(virtualHosts, vh) + } + } + + vh, err := b.buildVirtualHost(cfg.Options, "catch-all", "*", false) + if err != nil { + return nil, err + } + virtualHosts = append(virtualHosts, vh) + + rc, err := b.buildRouteConfiguration("main", virtualHosts) + if err != nil { + return nil, err + } + + return rc, nil +} diff --git a/internal/controlplane/xds.go b/internal/controlplane/xds.go index 7ceee105b..c1ace5ed5 100644 --- a/internal/controlplane/xds.go +++ b/internal/controlplane/xds.go @@ -11,8 +11,9 @@ import ( ) const ( - clusterTypeURL = "type.googleapis.com/envoy.config.cluster.v3.Cluster" - listenerTypeURL = "type.googleapis.com/envoy.config.listener.v3.Listener" + clusterTypeURL = "type.googleapis.com/envoy.config.cluster.v3.Cluster" + listenerTypeURL = "type.googleapis.com/envoy.config.listener.v3.Listener" + routeConfigurationTypeURL = "type.googleapis.com/envoy.config.route.v3.RouteConfiguration" ) func (srv *Server) buildDiscoveryResources(ctx context.Context) (map[string][]*envoy_service_discovery_v3.Resource, error) { @@ -44,5 +45,18 @@ func (srv *Server) buildDiscoveryResources(ctx context.Context) (map[string][]*e Resource: any, }) } + + routeConfigurations, err := srv.Builder.BuildRouteConfigurations(ctx, cfg.Config) + if err != nil { + return nil, err + } + for _, routeConfiguration := range routeConfigurations { + resources[routeConfigurationTypeURL] = append(resources[routeConfigurationTypeURL], &envoy_service_discovery_v3.Resource{ + Name: routeConfiguration.Name, + Version: hex.EncodeToString(cryptutil.HashProto(routeConfiguration)), + Resource: protoutil.NewAny(routeConfiguration), + }) + } + return resources, nil }