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?
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
requestobject and return therequestobject from the function so that CloudFront will continue onto theoriginrather than immediately returning aresponse.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With