简体   繁体   中英

accessing origin URL from AWS lambda@edge

I'm trying to implement a "proxy" to multiple websites using lambda@edge on AWS Cloudfront.

My setup is roughly:

DNS: *.domain.com -> some_uuid.cloudfront.net (Cloudfront distribution)

Cloudfront: some_uuid.cloudfront.net -> s3 bucket origin

s3 bucket: websites/ (a folder that contains multiple websites)

lambda@edge function: defined as origin-request

My lambda@edge function is quite simple:

  1. check if the website resource exists in the s3 bucket.

  2. if it does, change the request uri to the resource s3 url.

  3. if not, send a request to a backend server to render the resource, store on s3 and return it.

I'm having trouble getting the origin domain of the website. For example, if I try to access "my_website.domain.com" - in my lambda function i don't have this domain info from the request.

I think I can implement another lambda@edge function as viewer request to pass the domain as a header, but if I can, I prefer to avoid that.

Is there any other solution?

Thanks

The primary problem here is that Cloudfront overwrites the host header in the request to the origin host. I was able to workaround this by using a combination of viewer-request L@E and origin-request L@E.

In the viewer request L@E copy the host header into another header like x-forwarded-host.

// viewer-request.js
exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request
    request.headers['x-forwarded-host'] = [
      { key: 'X-Forwarded-Host', value: request.headers.host[0].value }
    ]
    return callback(null, request)
}

Configure your cloudfront to whitelist x-forwarded-host host header in the behaviour. This way the Cloudfront also takes into consideration the x-forwarded-host when caching and also passes the header along to the origin-request lambda .

So now in your origin-request lambda you can access the x-forwarded-host header

// origin-request.js
exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;
    const requestHost = headers['x-forwarded-host'][0].value;
    console.log(requestHost);
    callback(null, request);
}

So the problem with your use case is that the value of the host header exposed to your origin-request L@E function is the domain name of the s3 bucket, and not the original host header CloudFront has received from a viewer, correct?

In order to see the original Host header CloudFront received from the viewer, you need to whitelist it. However, CloudFront currently doesn't allow to whitelist headers for s3 origins. This is a bug/limitation that should be fixed by CloudFront. There is a workaround though. If the s3 bucket is publicly accessible (ie you are not using origin access identity), you can configure your S3 origin as a custom origin using a website endpoint like mybucket.s3-website-us-east-1.amazonaws.com. Then, you will be able to whitelist the host header and see the domain name of your website as requested by the viewer. You can then modify the origin request according to your use case. Don't forget also to change the host header back to the s3 endpoint so that S3 would accept the request.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM