-
Notifications
You must be signed in to change notification settings - Fork 1.1k
add aws lambda middleware #7353
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
💔 The detected issue is not in one of the allowed statuses 💔
Please ensure your jira story is in one of the allowed statuses |
PR Reviewer Guide 🔍
Here are some key observations to aid the review process:
Credential handling:
The middleware loads AWS config via default chain and optional endpoint override but does not honor explicit AccessKeyID/SecretAccessKey/AssumeRole settings in AWSCredentialsConfig. If users expect constrained credentials or role assumption, the default chain might pick broader creds, causing least-privilege violations. Additionally, API spec fields contain secrets—ensure they are redacted in logs and not exposed via analytics or debug output.
Possible Issue
Timeout calculation uses time.Duration(sec * float64(time.Second)) which won't compile (time.Duration expects integer types). It should use time.Duration(sec) * time.Second. This impacts default timeout when TimeoutMs <= 0.
// Prepare context with timeout timeout := time.Duration(cfg.TimeoutMs) * time.Millisecond if timeout <= 0 { // Convert seconds to duration; default to 30s if unset sec := m.Spec.GlobalConfig.ProxyDefaultTimeout if sec <= 0 { sec = 30 } timeout = time.Duration(sec * float64(time.Second)) } ctx, cancel := context.WithTimeout(r.Context(), timeout)
Security Concern
AWSCredentialsConfig includes access keys and secret in API spec; ensure they are not logged or exposed. Also, current AWS SDK setup ignores provided static credentials/assume role fields—only default chain/endpoint override is used. This may lead to unexpected credential sourcing and potential privilege issues.
func (m *AWSLambdaMiddleware) invokeLambda(ctx context.Context, cfg *apidef.AWSLambdaMeta, payload []byte) (*lambda.InvokeOutput, string, string, error) { // Load AWS config awsCfg, err := awsconfig.LoadDefaultConfig(ctx, awsconfig.WithRegion(cfg.Region)) if err != nil { return nil, "", "", err } var client *lambda.Client if cfg.Credentials.EndpointOverride != "" { // For LocalStack/testing endpoint := cfg.Credentials.EndpointOverride client = lambda.NewFromConfig(awsCfg, func(o *lambda.Options) { o.BaseEndpoint = &endpoint }) } else { client = lambda.NewFromConfig(awsCfg) }
Incomplete Mapping
RequestMapping header/query allow lists and flags are effectively ignored (conditions default to forwarding all regardless of booleans). Also Path stripping logic may be inverted; ForwardPath true should forward full path or stripped path consistently. Validate intended semantics.
// Path as seen by upstream path := r.URL.Path if mapping.ForwardPath { path = m.Spec.StripListenPath(path) } // Headers singleHeaders := map[string]string{} multiHeaders := map[string][]string{} if mapping.ForwardHeaders || !mapping.ForwardHeaders { // default: forward all for k, v := range r.Header { multiHeaders[k] = v if len(v) > 0 { singleHeaders[k] = v[0] } } } // Query params singleQuery := map[string]string{} multiQuery := map[string][]string{} if mapping.ForwardQuerystring || !mapping.ForwardQuerystring { // default true q := r.URL.Query() for k, v := range q { multiQuery[k] = v if len(v) > 0 { singleQuery[k] = v[0] } } } // Body isB64 := false var bodyStr string if mapping.ForwardBody || !mapping.ForwardBody { // default true if mapping.Base64EncodeBody { bodyStr = base64.StdEncoding.EncodeToString(bodyBytes) isB64 = true } else { bodyStr = string(bodyBytes) } }
API Changes
--- prev.txt 2025年09月12日 14:22:46.296050409 +0000 +++ current.txt 2025年09月12日 14:22:36.658903463 +0000 @@ -334,6 +334,59 @@ SetDisabledFlags set disabled flags to true, since by default they are not enabled in OAS API definition. +type AWSCredentialsConfig struct { + UseSDKDefaultChain bool `bson:"use_sdk_default_chain" json:"use_sdk_default_chain"` + AccessKeyID string `bson:"access_key_id" json:"access_key_id,omitempty"` + SecretAccessKey string `bson:"secret_access_key" json:"secret_access_key,omitempty"` + SessionToken string `bson:"session_token" json:"session_token,omitempty"` + AssumeRoleARN string `bson:"assume_role_arn" json:"assume_role_arn,omitempty"` + ExternalID string `bson:"external_id" json:"external_id,omitempty"` + EndpointOverride string `bson:"endpoint_override" json:"endpoint_override,omitempty"` +} + AWSCredentialsConfig configures how credentials are resolved for Lambda + invocation. + +type AWSLambdaMeta struct { + Disabled bool `bson:"disabled" json:"disabled"` + Path string `bson:"path" json:"path"` + Method string `bson:"method" json:"method"` + FunctionName string `bson:"function_name" json:"function_name"` + Qualifier string `bson:"qualifier" json:"qualifier,omitempty"` + Region string `bson:"region" json:"region"` + InvocationType string `bson:"invocation_type" json:"invocation_type"` + TimeoutMs int `bson:"timeout_ms" json:"timeout_ms"` + + Credentials AWSCredentialsConfig `bson:"credentials" json:"credentials"` + RequestMapping AWSLambdaRequestMapping `bson:"request_mapping" json:"request_mapping"` + ResponseMapping AWSLambdaResponseMapping `bson:"response_mapping" json:"response_mapping"` +} + AWSLambdaMeta defines per-path AWS Lambda invocation configuration. + +type AWSLambdaRequestMapping struct { + Mode string `bson:"mode" json:"mode"` + ForwardBody bool `bson:"forward_body" json:"forward_body"` + ForwardHeaders bool `bson:"forward_headers" json:"forward_headers"` + ForwardQuerystring bool `bson:"forward_querystrings" json:"forward_querystrings"` + ForwardPath bool `bson:"forward_path" json:"forward_path"` + PayloadVersion string `bson:"payload_version" json:"payload_version"` + Base64EncodeBody bool `bson:"base64_encode_body" json:"base64_encode_body"` + HeaderAllowList []string `bson:"header_allow_list" json:"header_allow_list,omitempty"` + QueryAllowList []string `bson:"query_allow_list" json:"query_allow_list,omitempty"` +} + AWSLambdaRequestMapping controls how HTTP requests are converted into Lambda + payloads. + +type AWSLambdaResponseMapping struct { + Mode string `bson:"mode" json:"mode"` + DefaultStatus int `bson:"default_status" json:"default_status"` + ErrorStatus int `bson:"error_status" json:"error_status"` + DecodeBase64Body bool `bson:"decode_base64_body" json:"decode_base64_body"` + UnhandledStatus int `bson:"unhandled_status" json:"unhandled_status"` + HeaderPassthrough bool `bson:"header_passthrough" json:"header_passthrough"` +} + AWSLambdaResponseMapping controls how Lambda responses are mapped to HTTP + responses. + type AnalyticsPluginConfig struct { // Enabled activates the custom plugin Enabled bool `bson:"enable" json:"enable,omitempty"` @@ -513,6 +566,7 @@ CircuitBreaker []CircuitBreakerMeta `bson:"circuit_breakers" json:"circuit_breakers,omitempty"` URLRewrite []URLRewriteMeta `bson:"url_rewrites" json:"url_rewrites,omitempty"` Virtual []VirtualMeta `bson:"virtual" json:"virtual,omitempty"` + AWSLambda []AWSLambdaMeta `bson:"aws_lambda" json:"aws_lambda,omitempty"` SizeLimit []RequestSizeMeta `bson:"size_limits" json:"size_limits,omitempty"` MethodTransforms []MethodTransformMeta `bson:"method_transforms" json:"method_transforms,omitempty"` TrackEndpoints []TrackEndpointMeta `bson:"track_endpoints" json:"track_endpoints,omitempty"` @@ -9172,6 +9226,21 @@ Version attempts to extract the version data from a request, depending on where it is stored in the request (currently only "header" is supported) +type AWSLambdaMiddleware struct { + *BaseMiddleware + + // Has unexported fields. +} + AWSLambdaMiddleware invokes AWS Lambda functions for matching endpoints. + +func (m *AWSLambdaMiddleware) EnabledForSpec() bool + +func (m *AWSLambdaMiddleware) Init() + +func (m *AWSLambdaMiddleware) Name() string + +func (m *AWSLambdaMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) + type AccessRightsCheck struct { *BaseMiddleware } @@ -11401,6 +11470,7 @@ StatusGoPlugin RequestStatus = "Go plugin" StatusPersistGraphQL RequestStatus = "Persist GraphQL" StatusRateLimit RequestStatus = "Rate Limited" + StatusAWSLambda RequestStatus = "AWS Lambda" ) Statuses of the request, all are false-y except StatusOk and StatusOkAndIgnore @@ -12012,6 +12082,7 @@ GoPluginMeta GoPluginMiddleware PersistGraphQL apidef.PersistGraphQLMeta RateLimit apidef.RateLimitMeta + AWSLambda apidef.AWSLambdaMeta IgnoreCase bool // Has unexported fields. @@ -12048,6 +12119,7 @@ GoPlugin PersistGraphQL RateLimit + AWSLambda ) Enums representing the various statuses for a VersionInfo Path match during a proxy request
PR Code Suggestions ✨Explore these optional code suggestions:
|
🚀 Performance Snapshot
## Performance Impact AnalysisThe new AWS Lambda middleware introduces external service dependencies that could impact gateway performance. Each request to a Lambda endpoint creates a new AWS SDK client, makes network calls to AWS Lambda, and performs JSON marshaling/unmarshaling operations. These operations add latency and resource overhead to the request processing path. The middleware is positioned before VirtualEndpoint in the chain, so it will be executed for all requests matching Lambda paths, potentially adding overhead even when Lambda functions aren't invoked. ## Critical Areas
## Optimization Recommendations
## Summary
Tip: Mention me again using |
📦 Impact Review Snapshot
## Impact AssessmentThis PR adds AWS Lambda integration to the Tyk Gateway, introducing new API definition fields and middleware. The changes primarily impact tyk-operator which needs to understand the new API definition schema, and portal which would need UI components to configure Lambda integrations. The changes are additive and shouldn't break existing functionality, but downstream repositories need updates to fully support this feature. ## Required Updatestyk-operator:
portal:
tyk-charts:
tyk-sink:
## Compatibility Concerns
## Summary & Recommendations
Tip: Mention me again using |
🚦 Connectivity Review Snapshot
## Connectivity Assessment
## Test Coverage Validation
## Security & Performance Impact
## Summary & Recommendations
Tip: Mention me again using |
Uh oh!
There was an error while loading. Please reload this page.
User description
TT-982
PR Type
Enhancement
Description
Add AWS Lambda middleware integration
Extend API spec with Lambda config
Compile/match Lambda paths in loader
Map Lambda responses to HTTP
Diagram Walkthrough
File Walkthrough
api_definitions.go
Add AWS Lambda configuration types to API definitions
apidef/api_definitions.go
AWSLambda
toExtendedPathsSet
.AWSLambdaMeta
configuration struct.api_definition.go
Wire AWS Lambda into URL status and path compilation
gateway/api_definition.go
AWSLambda
URLStatus and status string.StatusAWSLambda
.api_loader.go
Add AWSLambdaMiddleware to request processing chain
gateway/api_loader.go
AWSLambdaMiddleware
in middleware chain.model_urlspec.go
Extend URLSpec to support AWS Lambda matching
gateway/model_urlspec.go
AWSLambda
field toURLSpec
.mw_aws_lambda.go
Implement AWS Lambda invocation middleware
gateway/mw_aws_lambda.go
AWSLambdaMiddleware
with enablement logic.