diff --git a/.changelog/12681.txt b/.changelog/12681.txt new file mode 100644 index 0000000000..6147703321 --- /dev/null +++ b/.changelog/12681.txt @@ -0,0 +1,3 @@ +```release-note:feature +xds: Add the ability to invoke AWS Lambdas through terminating gateways. +``` diff --git a/agent/xds/serverless_plugin_oss_test.go b/agent/xds/serverless_plugin_oss_test.go index 20c9a4d2d3..5fbfdc1c6d 100644 --- a/agent/xds/serverless_plugin_oss_test.go +++ b/agent/xds/serverless_plugin_oss_test.go @@ -80,6 +80,15 @@ func TestServerlessPluginFromSnapshot(t *testing.T) { } }, }, + { + name: "routes", + key: xdscommon.RouteType, + sorter: func(msgs []proto.Message) func(int, int) bool { + return func(i, j int) bool { + return msgs[i].(*envoy_listener_v3.Listener).Name < msgs[j].(*envoy_listener_v3.Listener).Name + } + }, + }, } for _, entity := range entities { diff --git a/agent/xds/serverlessplugin/lambda_patcher.go b/agent/xds/serverlessplugin/lambda_patcher.go index 5121a36df5..c5d54d9cfa 100644 --- a/agent/xds/serverlessplugin/lambda_patcher.go +++ b/agent/xds/serverlessplugin/lambda_patcher.go @@ -8,6 +8,7 @@ import ( envoy_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" envoy_endpoint_v3 "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" + envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" envoy_lambda_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/aws_lambda/v3" envoy_http_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" envoy_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" @@ -78,6 +79,28 @@ func (p lambdaPatcher) CanPatch(kind api.ServiceKind) bool { return kind == p.kind } +func (p lambdaPatcher) PatchRoute(route *envoy_route_v3.RouteConfiguration) (*envoy_route_v3.RouteConfiguration, bool, error) { + if p.kind != api.ServiceKindTerminatingGateway { + return route, false, nil + } + + for _, virtualHost := range route.VirtualHosts { + for _, route := range virtualHost.Routes { + action, ok := route.Action.(*envoy_route_v3.Route_Route) + + if !ok { + continue + } + + // When auto_host_rewrite is set it conflicts with strip_any_host_port + // on the http_connection_manager filter. + action.Route.HostRewriteSpecifier = nil + } + } + + return route, true, nil +} + func (p lambdaPatcher) PatchCluster(c *envoy_cluster_v3.Cluster) (*envoy_cluster_v3.Cluster, bool, error) { transportSocket, err := makeUpstreamTLSTransportSocket(&envoy_tls_v3.UpstreamTlsContext{ Sni: "*.amazonaws.com", @@ -160,7 +183,9 @@ func (p lambdaPatcher) PatchFilter(filter *envoy_listener_v3.Filter) (*envoy_lis httpFilter, {Name: "envoy.filters.http.router"}, } - config.StripMatchingHostPort = true + config.StripPortMode = &envoy_http_v3.HttpConnectionManager_StripAnyHostPort{ + StripAnyHostPort: true, + } newFilter, err := makeFilter("envoy.filters.network.http_connection_manager", config) if err != nil { return filter, false, errors.New("error making new filter") diff --git a/agent/xds/serverlessplugin/patcher.go b/agent/xds/serverlessplugin/patcher.go index 58847bcb6f..8db1c95a1b 100644 --- a/agent/xds/serverlessplugin/patcher.go +++ b/agent/xds/serverlessplugin/patcher.go @@ -3,6 +3,7 @@ package serverlessplugin import ( envoy_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" + envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" "github.com/hashicorp/consul/agent/xds/xdscommon" "github.com/hashicorp/consul/api" @@ -15,6 +16,11 @@ type patcher interface { // CanPatch determines if the patcher can mutate resources for the given api.ServiceKind CanPatch(api.ServiceKind) bool + // patchRoute patches a route to include the custom Envoy configuration + // PatchCluster patches a cluster to include the custom Envoy configuration + // required to integrate with the serverless integration. + PatchRoute(*envoy_route_v3.RouteConfiguration) (*envoy_route_v3.RouteConfiguration, bool, error) + // PatchCluster patches a cluster to include the custom Envoy configuration // required to integrate with the serverless integration. PatchCluster(*envoy_cluster_v3.Cluster) (*envoy_cluster_v3.Cluster, bool, error) diff --git a/agent/xds/serverlessplugin/serverlessplugin.go b/agent/xds/serverlessplugin/serverlessplugin.go index 8ab38e3744..1d7387000b 100644 --- a/agent/xds/serverlessplugin/serverlessplugin.go +++ b/agent/xds/serverlessplugin/serverlessplugin.go @@ -5,6 +5,7 @@ import ( envoy_cluster_v3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" envoy_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" + envoy_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" "github.com/golang/protobuf/proto" "github.com/hashicorp/go-multierror" @@ -30,6 +31,7 @@ func MutateIndexedResources(resources *xdscommon.IndexedResources, config xdscom for _, indexType := range []string{ xdscommon.ClusterType, xdscommon.ListenerType, + xdscommon.RouteType, } { for nameOrSNI, msg := range resources.Index[indexType] { switch resource := msg.(type) { @@ -58,6 +60,21 @@ func MutateIndexedResources(resources *xdscommon.IndexedResources, config xdscom resources.Index[xdscommon.ListenerType][nameOrSNI] = newListener } + case *envoy_route_v3.RouteConfiguration: + patcher := getPatcherBySNI(config, config.Kind, nameOrSNI) + if patcher == nil { + continue + } + + newRoute, patched, err := patcher.PatchRoute(resource) + if err != nil { + resultErr = multierror.Append(resultErr, fmt.Errorf("error patching route: %w", err)) + continue + } + if patched { + resources.Index[xdscommon.RouteType][nameOrSNI] = newRoute + } + default: resultErr = multierror.Append(resultErr, fmt.Errorf("unsupported type was skipped: %T", resource)) } diff --git a/agent/xds/testdata/serverless_plugin/listeners/lambda-terminating-gateway.envoy-1-20-x.golden b/agent/xds/testdata/serverless_plugin/listeners/lambda-terminating-gateway.envoy-1-20-x.golden index e0b77f6f47..d412ef5ce3 100644 --- a/agent/xds/testdata/serverless_plugin/listeners/lambda-terminating-gateway.envoy-1-20-x.golden +++ b/agent/xds/testdata/serverless_plugin/listeners/lambda-terminating-gateway.envoy-1-20-x.golden @@ -211,7 +211,7 @@ } }, - "stripMatchingHostPort": true + "stripAnyHostPort": true } } ], @@ -269,4 +269,4 @@ ], "typeUrl": "type.googleapis.com/envoy.config.listener.v3.Listener", "nonce": "00000001" -} \ No newline at end of file +} diff --git a/agent/xds/testdata/serverless_plugin/routes/lambda-terminating-gateway.envoy-1-20-x.golden b/agent/xds/testdata/serverless_plugin/routes/lambda-terminating-gateway.envoy-1-20-x.golden new file mode 100644 index 0000000000..4cefff9c6f --- /dev/null +++ b/agent/xds/testdata/serverless_plugin/routes/lambda-terminating-gateway.envoy-1-20-x.golden @@ -0,0 +1,30 @@ +{ + "versionInfo": "00000001", + "resources": [ + { + "@type": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "name": "web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "virtualHosts": [ + { + "name": "web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "web.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul" + } + } + ] + } + ], + "validateClusters": true + } + ], + "typeUrl": "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + "nonce": "00000001" +} \ No newline at end of file