Peterhack
Peterhack

Reputation: 1061

Cloudfront: Forward host header to lambda function URL origin

I have deployed the new Lambda function URL feature with a Cloudfront distribution to enable a custom domain. However, my backend needs the real host head and not the one Cloudfront rewrites (see host here), in this case to the function URL https://xxxxxxxx.lambda-url.eu-central-1.on.aws/.

I also tried using the managed origin request policy AllViewer, but this neither works and in the browser it returns: "Message: null" and the x-cache header says cloudfront error.

My config currently looks like this:

CloudFrontDistribution:
  Type: AWS::CloudFront::Distribution
  Properties:
    DistributionConfig:
      PriceClass: PriceClass_100
      HttpVersion: http2
      IPV6Enabled: true
      Comment: Distribution for Lambda Function URL
      Origins:
        # extract function url form your lambda resource
      - DomainName: !Select [2, !Split ["/", !GetAtt ApiLambdaFunctionUrl.FunctionUrl]]
        Id: LambdaOrigin
        CustomOriginConfig:
          HTTPSPort: 443
          OriginProtocolPolicy: https-only
      Enabled: 'true'
      DefaultCacheBehavior:
        TargetOriginId: LambdaOrigin
        # Disable caching as http api did not allow either
        CachePolicyId: '4135ea2d-6df8-44a3-9df3-4b5a84be39ad'
        ViewerProtocolPolicy: redirect-to-https
        SmoothStreaming: 'false'
        Compress: 'true'
      Aliases:
        - sub.domain.com
      ViewerCertificate:
        SslSupportMethod: sni-only
        MinimumProtocolVersion: TLSv1.2_2019
        AcmCertificateArn: xxxxx
FunctionRecordSetGroup:
  Type: AWS::Route53::RecordSetGroup
  DeletionPolicy: Delete
  DependsOn:
    - CloudFrontDistribution
  Properties:
    HostedZoneName: domain.com.
    RecordSets:
      - Name: sub.domain.com
        Type: A
        AliasTarget:
          # The following HosteZoneId is always used for alias records pointing to CF.
          HostedZoneId: Z2FDTNDATAQYW2
          DNSName: { 'Fn::GetAtt': [CloudFrontDistribution, DomainName] }

How can I achieve forwarding the host header?

Upvotes: 3

Views: 3234

Answers (2)

Jay
Jay

Reputation: 61

I had the same issue with CloudFront when parsing the host header via the origin_request and origin_response Lambda@Edge functions since the header contains the value of the origin because that is the request's destination. The request/response Lambdas are book-end functions that run before and after the call to the origin server.

In the case of @peterhack (OP), the Lambda function URL is the origin without utilizing Lambda@Edge request/response interceptors, but the principle is the same.

A CloudFront Function receives the correct host header because it receives the original viewer_request event. Since one cannot meaningfully overwrite the host header, I substituted a generic header viewer-host to receive the value:

// Cloudfront Function (ES5)
// viewer_request
function handler(event) {
    var request = event.request;

    request.headers["viewer-host"] = request.headers.host;

    return request;
}

Note: Here, we add the header to the request object and return the request object from the function so that CloudFront will continue onto the origin rather than immediately returning a response.

If you have trouble, AWS provides a similar example for modifying the request headers and includes links to more information.

Additionally, you will need to manually add the new header to the Origin Request Policy since AllViewer cannot be used for a Lambda origin because it forwards the wrong header as indicated by @carlos-garces in this thread.


With the Cloudfront Function in place, modify your Lambda function to parse the new header.

Lambda@Edge example:

const hostHeader = event.Records[0].cf.request.headers['viewer-host'][0].value

Lambda origin URL example:

const hostHeader = event.headers['viewer-host']

One drawback is that your CloudFront Distribution will always run a CloudFront Function regardless of origin caching, and your desired origin Lambda will incur an additional Lambda invocation count, but only when reaching the origin.

With 2,000,000 free CloudFront Function invocations per month, there is a buffer until incurring an added cost. Depending on your use case, it may fit within the free tier.

Upvotes: 1

Carlos Garces
Carlos Garces

Reputation: 833

The key is the host http header You need to use " https://xxxxxxxx.lambda-url.eu-central-1.on.aws/." as host header otherwise will not work. Please check this anwser.

https://stackoverflow.com/a/73364712

Upvotes: -1

Related Questions