Skip to content

Commit

Permalink
Support making requests to lambda from connect proxies.
Browse files Browse the repository at this point in the history
  • Loading branch information
erichaberkorn committed May 5, 2022
1 parent d4eef44 commit 21c3134
Show file tree
Hide file tree
Showing 15 changed files with 540 additions and 89 deletions.
3 changes: 3 additions & 0 deletions .changelog/12956.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
xds: Add the ability to invoke AWS Lambdas through sidecar proxies.
```
19 changes: 19 additions & 0 deletions agent/xds/serverless_plugin_oss_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,36 @@ import (
"github.com/stretchr/testify/require"

"github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/agent/xds/proxysupport"
"github.com/hashicorp/consul/agent/xds/serverlessplugin"
"github.com/hashicorp/consul/agent/xds/xdscommon"
"github.com/hashicorp/consul/sdk/testutil"
)

func TestServerlessPluginFromSnapshot(t *testing.T) {
serviceDefaults := &structs.ServiceConfigEntry{
Kind: structs.ServiceDefaults,
Name: "db",
Protocol: "http",
Meta: map[string]string{
"serverless.consul.hashicorp.com/v1alpha1/lambda/enabled": "true",
"serverless.consul.hashicorp.com/v1alpha1/lambda/arn": "lambda-arn",
"serverless.consul.hashicorp.com/v1alpha1/lambda/payload-passthrough": "true",
"serverless.consul.hashicorp.com/v1alpha1/lambda/region": "us-east-1",
},
}

tests := []struct {
name string
create func(t testinf.T) *proxycfg.ConfigSnapshot
}{
{
name: "lambda-connect-proxy",
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
return proxycfg.TestConfigSnapshotDiscoveryChain(t, "default", nil, nil, serviceDefaults)
},
},
{
name: "lambda-terminating-gateway",
create: func(t testinf.T) *proxycfg.ConfigSnapshot {
Expand Down
23 changes: 15 additions & 8 deletions agent/xds/serverlessplugin/patcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,30 @@ type patcher interface {

type patchers map[api.CompoundServiceName]patcher

func getPatcher(patchers patchers, kind api.ServiceKind, name api.CompoundServiceName) patcher {
patcher, ok := patchers[name]
// getPatcherBySNI gets the patcher for the associated SNI.
func getPatcherBySNI(config xdscommon.PluginConfiguration, sni string) patcher {
serviceName, ok := config.SNIToServiceName[sni]

if !ok {
return nil
}

if !patcher.CanPatch(kind) {
serviceConfig, ok := config.ServiceConfigs[serviceName]
if !ok {
return nil
}

return patcher
p := makePatcher(serviceConfig)
if p == nil || !p.CanPatch(config.Kind) {
return nil
}

return p
}

// getPatcherBySNI gets the patcher for the associated SNI.
func getPatcherBySNI(config xdscommon.PluginConfiguration, kind api.ServiceKind, sni string) patcher {
serviceName, ok := config.SNIToServiceName[sni]
// getPatcherByEnvoyID gets the patcher for the associated envoy id.
func getPatcherByEnvoyID(config xdscommon.PluginConfiguration, envoyID string) patcher {
serviceName, ok := config.EnvoyIDToServiceName[envoyID]

if !ok {
return nil
Expand All @@ -60,7 +67,7 @@ func getPatcherBySNI(config xdscommon.PluginConfiguration, kind api.ServiceKind,
}

p := makePatcher(serviceConfig)
if p == nil || !p.CanPatch(kind) {
if p == nil || !p.CanPatch(config.Kind) {
return nil
}

Expand Down
4 changes: 3 additions & 1 deletion agent/xds/serverlessplugin/patcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ func TestGetPatcherBySNI(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
config := sampleConfig()
config.Kind = tc.kind
if tc.config != nil {
config = *tc.config
}
patcher := getPatcherBySNI(config, tc.kind, tc.sni)
patcher := getPatcherBySNI(config, tc.sni)

if tc.expected == nil {
require.Empty(t, patcher)
Expand All @@ -69,6 +70,7 @@ var (

func sampleConfig() xdscommon.PluginConfiguration {
return xdscommon.PluginConfiguration{
Kind: api.ServiceKindTerminatingGateway,
ServiceConfigs: map[api.CompoundServiceName]xdscommon.ServiceConfig{
lambdaService: {
Kind: api.ServiceKindTerminatingGateway,
Expand Down
63 changes: 55 additions & 8 deletions agent/xds/serverlessplugin/serverlessplugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package serverlessplugin

import (
"fmt"
"strings"

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"
Expand All @@ -22,9 +23,9 @@ import (
func MutateIndexedResources(resources *xdscommon.IndexedResources, config xdscommon.PluginConfiguration) (*xdscommon.IndexedResources, error) {
var resultErr error

// The serverless plugin only supports terminating gateays for now, but will
// likely add connect proxies soon.
if config.Kind != api.ServiceKindTerminatingGateway {
switch config.Kind {
case api.ServiceKindTerminatingGateway, api.ServiceKindConnectProxy:
default:
return resources, resultErr
}

Expand All @@ -36,7 +37,7 @@ func MutateIndexedResources(resources *xdscommon.IndexedResources, config xdscom
for nameOrSNI, msg := range resources.Index[indexType] {
switch resource := msg.(type) {
case *envoy_cluster_v3.Cluster:
patcher := getPatcherBySNI(config, config.Kind, nameOrSNI)
patcher := getPatcherBySNI(config, nameOrSNI)
if patcher == nil {
continue
}
Expand All @@ -51,7 +52,7 @@ func MutateIndexedResources(resources *xdscommon.IndexedResources, config xdscom
}

case *envoy_listener_v3.Listener:
newListener, patched, err := patchTerminatingGatewayListener(resource, config)
newListener, patched, err := patchListener(config, resource)
if err != nil {
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener: %w", err))
continue
Expand All @@ -61,7 +62,7 @@ func MutateIndexedResources(resources *xdscommon.IndexedResources, config xdscom
}

case *envoy_route_v3.RouteConfiguration:
patcher := getPatcherBySNI(config, config.Kind, nameOrSNI)
patcher := getPatcherBySNI(config, nameOrSNI)
if patcher == nil {
continue
}
Expand All @@ -84,7 +85,17 @@ func MutateIndexedResources(resources *xdscommon.IndexedResources, config xdscom
return resources, resultErr
}

func patchTerminatingGatewayListener(l *envoy_listener_v3.Listener, config xdscommon.PluginConfiguration) (proto.Message, bool, error) {
func patchListener(config xdscommon.PluginConfiguration, l *envoy_listener_v3.Listener) (proto.Message, bool, error) {
switch config.Kind {
case api.ServiceKindTerminatingGateway:
return patchTerminatingGatewayListener(config, l)
case api.ServiceKindConnectProxy:
return patchConnectProxyListener(config, l)
}
return l, false, nil
}

func patchTerminatingGatewayListener(config xdscommon.PluginConfiguration, l *envoy_listener_v3.Listener) (proto.Message, bool, error) {
var resultErr error
patched := false
for _, filterChain := range l.FilterChains {
Expand All @@ -94,7 +105,7 @@ func patchTerminatingGatewayListener(l *envoy_listener_v3.Listener, config xdsco
continue
}

patcher := getPatcherBySNI(config, config.Kind, sni)
patcher := getPatcherBySNI(config, sni)

if patcher == nil {
continue
Expand All @@ -120,6 +131,42 @@ func patchTerminatingGatewayListener(l *envoy_listener_v3.Listener, config xdsco
return l, patched, resultErr
}

func patchConnectProxyListener(config xdscommon.PluginConfiguration, l *envoy_listener_v3.Listener) (proto.Message, bool, error) {
var resultErr error

envoyID := ""
if i := strings.IndexByte(l.Name, ':'); i != -1 {
envoyID = l.Name[:i]
}

patcher := getPatcherByEnvoyID(config, envoyID)
if patcher == nil {
return l, false, nil
}

var patched bool

for _, filterChain := range l.FilterChains {
var filters []*envoy_listener_v3.Filter

for _, filter := range filterChain.Filters {
newFilter, ok, err := patcher.PatchFilter(filter)
if err != nil {
resultErr = multierror.Append(resultErr, fmt.Errorf("error patching listener filter: %w", err))
filters = append(filters, filter)
}

if ok {
filters = append(filters, newFilter)
patched = true
}
}
filterChain.Filters = filters
}

return l, patched, resultErr
}

func getSNI(chain *envoy_listener_v3.FilterChain) string {
var sni string

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,6 @@
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"forwardClientCertDetails": "APPEND_FORWARD",
"setCurrentClientCertDetails": {
"cert": true,
"chain": true,
"dns": true,
"subject": true,
"uri": true
},
"statPrefix": "public_listener",
"routeConfig": {
"name": "public_listener",
Expand Down Expand Up @@ -119,6 +111,14 @@
"randomSampling": {

}
},
"forwardClientCertDetails": "APPEND_FORWARD",
"setCurrentClientCertDetails": {
"subject": true,
"cert": true,
"chain": true,
"dns": true,
"uri": true
}
}
}
Expand Down
16 changes: 8 additions & 8 deletions agent/xds/testdata/listeners/http-public-listener.latest.golden
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,6 @@
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"forwardClientCertDetails": "APPEND_FORWARD",
"setCurrentClientCertDetails": {
"cert": true,
"chain": true,
"dns": true,
"subject": true,
"uri": true
},
"statPrefix": "public_listener",
"routeConfig": {
"name": "public_listener",
Expand Down Expand Up @@ -118,6 +110,14 @@
"randomSampling": {

}
},
"forwardClientCertDetails": "APPEND_FORWARD",
"setCurrentClientCertDetails": {
"subject": true,
"cert": true,
"chain": true,
"dns": true,
"uri": true
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,6 @@
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"forwardClientCertDetails": "APPEND_FORWARD",
"setCurrentClientCertDetails": {
"cert": true,
"chain": true,
"dns": true,
"subject": true,
"uri": true
},
"statPrefix": "upstream.web.default.default.dc1",
"rds": {
"configSource": {
Expand Down Expand Up @@ -223,6 +215,14 @@
"randomSampling": {

}
},
"forwardClientCertDetails": "APPEND_FORWARD",
"setCurrentClientCertDetails": {
"subject": true,
"cert": true,
"chain": true,
"dns": true,
"uri": true
}
}
}
Expand Down Expand Up @@ -266,14 +266,6 @@
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"forwardClientCertDetails": "APPEND_FORWARD",
"setCurrentClientCertDetails": {
"cert": true,
"chain": true,
"dns": true,
"subject": true,
"uri": true
},
"statPrefix": "upstream.web.default.default.dc1",
"rds": {
"configSource": {
Expand Down Expand Up @@ -305,6 +297,14 @@
"randomSampling": {

}
},
"forwardClientCertDetails": "APPEND_FORWARD",
"setCurrentClientCertDetails": {
"subject": true,
"cert": true,
"chain": true,
"dns": true,
"uri": true
}
}
}
Expand Down Expand Up @@ -348,14 +348,6 @@
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"forwardClientCertDetails": "APPEND_FORWARD",
"setCurrentClientCertDetails": {
"cert": true,
"chain": true,
"dns": true,
"subject": true,
"uri": true
},
"statPrefix": "upstream.web.default.default.dc1",
"rds": {
"configSource": {
Expand Down Expand Up @@ -387,6 +379,14 @@
"randomSampling": {

}
},
"forwardClientCertDetails": "APPEND_FORWARD",
"setCurrentClientCertDetails": {
"subject": true,
"cert": true,
"chain": true,
"dns": true,
"uri": true
}
}
}
Expand Down
Loading

0 comments on commit 21c3134

Please sign in to comment.