AWS ALB Jersey Lambda Target Gotchas

Thinking about using an AWS Lambda function using the excellent awslabs/aws-serverless-java-container as an AWS Application Load Balancer (ALB) target? There are some configuration gotchas you should know about!

ALB Lambda Target Configuration

When you set up an ALB target group, you can configure the group using Target Group Attributes. For Lambda functions, the attribute lambda.multi_value_headers.enabled is set to false by default. This causes the ALB to send proxy web requests to the Lambda using single-value query parameter and header mappings:

{
  "requestContext": {
    "elb": {
      "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/prod-example-function/e77803ebb6d2c24"
    }
  },
  "httpMethod": "PUT",
  "path": "/path/to/resource",
  "queryStringParameters": {},
  "headers": {
    "accept": "*",
    "content-length": "17",
    "content-type": "application/json",
    "host": "stackoverflow.name",
    "user-agent": "curl/7.77.0",
    "x-amzn-trace-id": "Root=1-62e22402-3a5f246225e45edd7735c182",
    "x-forwarded-for": "24.14.13.186",
    "x-forwarded-port": "443",
    "x-forwarded-proto": "https",
    "x-jersey-tracing-accept": "true"
  },
  "body": "{\"alpha\":\"bravo\"}",
  "isBase64Encoded": false
}

The Problem

As of the time of this writing, the awslabs/aws-serverless-java-container library does not parse those single-value maps properly. This means the Lambda function doesn’t receive request headers or query parameters, which causes a variety of issues. In my case, the problem was POST and PUT requests resulting in a HTTP 415 Unsupported Media Type response even though those endpoints worked in another container.

The Solution

Fortunately, the solution is simple: just set lambda.multi_value_headers.enabled to true. This causes the ALB to send multi-value maps instead:

{
  "requestContext": {
    "elb": {
      "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/prod-example-function/e77803ebb6d2c24"
    }
  },
  "httpMethod": "PUT",
  "path": "/path/to/resource",
  "multiValueQueryStringParameters": {},
  "multiValueHeaders": {
    "accept": [
      "*"
    ],
    "content-length": [
      "17"
    ],
    "content-type": [
      "application/json"
    ],
    "host": [
      "stackoverflow.name"
    ],
    "user-agent": [
      "curl/7.77.0"
    ],
    "x-amzn-trace-id": [
      "Root=1-62e22402-3a5f246225e45edd7735c182"
    ],
    "x-forwarded-for": [
      "24.14.13.186"
    ],
    "x-forwarded-port": [
      "443"
    ],
    "x-forwarded-proto": [
      "https"
    ],
    "x-jersey-tracing-accept": [
      "true"
    ]
  },
  "body": "{\"alpha\":\"bravo\"}",
  "isBase64Encoded": false
}

The awslabs/aws-serverless-java-container library parses these values happily.

The Fix

I’ve proposed a fix to the code that would handle the single-valued maps properly and an update to the docs that would call out this configuration change more clearly. I’ll update here if and when those PRs get merged!