solo-io / gloo

The Feature-rich, Kubernetes-native, Next-Generation API Gateway Built on Envoy
https://docs.solo.io/
Apache License 2.0
4.04k stars 432 forks source link

Gloo Edge does not populate the identity object with the relevant data when wrapAsApiGateway is enabled #9541

Open sadieleob opened 1 month ago

sadieleob commented 1 month ago

Gloo Edge Product

Enterprise

Gloo Edge Version

1.16.8

Kubernetes Version

v1.27.13-eks-3af4770

Describe the bug

When setting GE to mimic the AWS API GW behavior by setting to true unwrapAsApiGateway and wrapAsApiGateway, it looks like GE might not be wrapping the request in a way that Lambda function expects.

AWS Lambda logs: java.lang.NullPointerException: Cannot invoke "com.amazonaws.serverless.proxy.model.ApiGatewayRequestIdentity.getAccessKey()" because the return value of "com.amazonaws.serverless.proxy.model.AwsProxyRequestContext.getIdentity()" is null

Expected Behavior

GE wraps the request to AWS Lambda in a manner identical to how API Gateway does, including fields such as the identity in the event object.

Steps to reproduce the bug

  1. Create AWS lambda:
mvn archetype:generate -DgroupId=my.service -DartifactId=my-service -Dversion=1.0-SNAPSHOT \
       -DarchetypeGroupId=com.amazonaws.serverless.archetypes \
       -DarchetypeArtifactId=aws-serverless-jersey-archetype \
       -DarchetypeVersion=2.0.1

Run "mvn clean package" to generate a zip file. Deploy the zip file in a Lambda function. Select Lambda Java version for the Lambda runtime same as what you have in pom.xml.

AWS Lambda

Testing Use following test event:

{
       "resource": "/ping",
       "path": "/ping",
       "httpMethod": "GET",
       "requestContext": {
           "stage": "stage1",
           "identity": {
             "apikey": "XXXXXXXXXXXXX",
             "userAgent": "curl/7.79.1"
           },
          "resourcePath": "/",
           "httpMethod": "GET",
           "path": "/"
       },
       "headers": {
            "Host": "www.example.com"
        },
        "multiValueHeaders": {
              "Host": ["www.example.com"]
        },
       "queryStringParameters": null,
       "multiValueQueryStringParameters": null,
       "pathParameters": null,
       "stageVariables": null,
       "body": null,
       "isBase64Encoded": false
   }
  1. Define the following VS and US:

    apiVersion: gloo.solo.io/v1
    kind: Upstream
    metadata:
    name: hello-lambda
    namespace: suresh
    spec:
    aws:
    destinationOverrides:
      requestTransformation: false
      unwrapAsApiGateway: true
      wrapAsApiGateway: true
    lambdaFunctions:
    - logicalName: sadiel-mvn
      qualifier: $LATEST
    region: us-west-2
    secretRef:
      name: aws-creds
      namespace: gloo-system
    connectionConfig:
    maxRequestsPerConnection: 1
    ---                                                                                                 
    apiVersion: gateway.solo.io/v1
    kind: VirtualService
    metadata:
    name: cbp-portal
    namespace: default
    spec:
    virtualHost:
    domains:
    - soloist.servebeer.com
    routes:
    - matchers:
      - prefix: /
      routeAction:
        single:
          destinationSpec:
            aws:
              logicalName: sadiel-mvn
          upstream:
            name: hello-lambda
            namespace: suresh
  2. GE Settings

    gloo:
    awsOptions:
      fallbackToFirstFunction: true
  3. Requests:

    
    curl -v -H"Host: soloist.servebeer.com" http://soloist.servebeer.com/v1/ping

curl -v -H"Host: soloist.servebeer.com" http://soloist.servebeer.com/v1/ping -H "api-key: $API_KEY" -H "Content-Type: application/json" -d '{"resource": "/ping","path": "/ping","httpMethod": "GET","requestContext": {"stage": "stage1","identity": {"apikey": "xxxxxxxxxx","userAgent": "curl/7.79.1"},"resourcePath": "/","httpMethod": "GET","path": "/"},"headers": {"Host": "www.example.com"},"multiValueHeaders": {"Host": ["www.example.com"]},"queryStringParameters": null,"multiValueQueryStringParameters": null,"pathParameters": null,"stageVariables": null,"body": null,"isBase64Encoded": false}'


5. Response:
{
  "upstream_host": "\"18.246.196.137:443\"",
  "method": "\"POST",
  "protocol": "HTTP/1.1\"",
  "path": "/2015-03-31/functions/sadiel-mvn/invocations?Qualifier=%24LATEST",
  "duration": 19,
  "response_code": 502,
  "upstreamCluster": "hello-lambda_suresh",
  "x-forwarded-for": "\"-\"",
  "response_flag": "-",
  "starttime": "[2024-05-29T17:28:57.019Z]",
  "request-id": "\"2699f1e0-6f5f-4947-9c70-65e7c6b48b8b\"",
  "requestHeaders": null,
  "upstreamHost": "18.246.196.137:443",
  "upstream_svc_time": null
}

### Additional Environment Detail

_No response_

### Additional Context

_No response_

┆Issue is synchronized with this [Asana task](https://app.asana.com/0/1206768562311555/1207720948241104) by [Unito](https://www.unito.io)
soloio-bot commented 1 month ago

Zendesk ticket #3749 has been linked to this issue.

sadieleob commented 1 month ago

tested in 1.16.10 and the issue persists.

helm list -n gloo-system                                                                                                                               
NAME    NAMESPACE   REVISION    UPDATED                                 STATUS      CHART           APP VERSION
gloo    gloo-system 17          2024-06-17 09:54:43.728908 -0500 CDT    deployed    gloo-ee-1.16.10

curl -v -H"Host: soloist.servebeer.com" http://soloist.servebeer.com/v1/ping -H "api-key: $API_KEY" -H "Content-Type: application/json" -d '{"resource": "/ping","path": "/ping","httpMethod": "GET","requestContext": {"stage": "stage1","identity": {"apikey": "xxxxxxxxxxxxx","userAgent": "curl/7.79.1"},"resourcePath": "/","httpMethod": "GET","path": "/"},"headers": {"Host": "www.example.com"},"multiValueHeaders": {"Host": ["www.example.com"]},"queryStringParameters": null,"multiValueQueryStringParameters": null,"pathParameters": null,"stageVariables": null,"body": null,"isBase64Encoded": false}'

* Host soloist.servebeer.com:80 was resolved.
* IPv6: (none)
* IPv4: 35.167.216.82
*   Trying 35.167.216.82:80...
* Connected to soloist.servebeer.com (35.167.216.82) port 80
> POST /v1/ping HTTP/1.1
> Host: soloist.servebeer.com
> User-Agent: curl/8.6.0
> Accept: */*
> api-key: xxxxxxxxxx
> Content-Type: application/json
> Content-Length: 485
>
< HTTP/1.1 502 Bad Gateway
< content-type: application/json
< content-length: 29
< x-ratelimit-limit: 1000
< x-ratelimit-remaining: 999
< x-ratelimit-reset: 1
< date: Mon, 17 Jun 2024 15:06:28 GMT
< server: envoy
<
* Connection #0 to host soloist.servebeer.com left intact
{"message": "Gateway Timeout"}%

2024-06-17T14:51:45.840Z
java.lang.NullPointerException: Cannot invoke "com.amazonaws.serverless.proxy.model.ApiGatewayRequestIdentity.getAccessKey()" because the return value of "com.amazonaws.serverless.proxy.model.AwsProxyRequestContext.getIdentity()" is null
DuncanDoyle commented 2 weeks ago

We need to make sure that we compare the full requests that are being sent by Gloo Edge with the full requests that are being sent by the AWS API Gateway to verify that there are no other fields and objects not being populated.

nrjpoddar commented 2 weeks ago

@nfuden to look at this issue for scope/estimation.