Route 53 alias DNS record: the alias target name does not lie within the target zone

半城伤御伤魂 提交于 2019-12-11 04:33:18

问题


I'm trying to set up an alias for a domain that is purchased through route 53. The alias is going to point to a page in my site with a URL like this:

http://example.com/website/:id

My api sets up a hostedZone with the following params:

  var params = {
    CallerReference: req.body.projectId,
    Name: req.body.domain, 
    HostedZoneConfig: {
      Comment: `the zone created on ${today} for ${req.body.domain}`,
      PrivateZone: false
    }
  };

In the next step, I'm setting up a DNS record with the following params:

var params = {
   ChangeBatch: {
    Changes: [
       {
      Action: "CREATE",
      ResourceRecordSet: {
       AliasTarget: {
        DNSName: `http://example.com/website/${req.body.projectId}`,
        EvaluateTargetHealth: false,
        HostedZoneId:  hostedZone.HostedZone.Id
       },
       Name: "example.com",
       Type: "A"
      }
     }
    ],
   },
   HostedZoneId: hostedZone.HostedZone.Id
  };

I get an error that my alias target name doesn't lie within the target zone. What step am I missing to set this up properly?


回答1:


DNS has no mechanism for handling paths, so what's being attempted here is something not possible in DNS. But it seems this was an attempt to solve a different problem.

Is there a way to route to a generic s3 bucket instead of a bucket with a matching name?

No... and yes.

S3 relies on what the browser thinks the hostname should be, as signified by the incoming Host header, in order to send the request to the correct bucket.

Thus when S3 is used by itself, if a DNS entry points to a bucket, the bucket name must exactly match the hostname.

For different behavior, such as http://bucket.example.com pointing to a bucket named example-bucket, you need a reverse proxy to handle header rewriting so that when the browser specifies Host: bucket.example.com, S3 receives a request with Host: example-bucket.s3.amazonaws.com.

CloudFront provides such a reverse proxy capability.

When configuring a CloudFront distribution, you specify an Origin Domain Name (pointing to the bucket) and an Alternate Domain Name, which specifies what you want CloudFront to expect from the browser. CloudFront rewrites the request in-flight so that what S3 sees differs from what the browser sends.

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/MigrateS3ToCloudFront.html

As noted on that page, the pricing structures of S3 and CloudFront are such that the cost difference between using S3 by itself or S3 + CloudFront can actually go either way -- it can actually cost slightly less to use both together, depending on the bucket location, the viewer location, the size of the objects, and the cache hit ratio (assuming you don't disable the CloudFront cache).

If you want https://website-1.example.com to be served from your example-bucket with a root path of website/1/ you can do that, too, but it gets a little trickier.

You can do this on a one-off, static basis by setting the Origin Path on the Origin configuration in CloudFront, since this field represents a path prefix that will be prepended onto each request before it's sent to the origin.

Or you can modify it dynamically using CloudFront with a Lambda@Edge trigger. Here's what that might look like.

'use strict';

// if the end of incoming Host header matches this string, 
// strip this part and prepend the remaining characters onto the request path,
// along with a new leading slash (otherwise, the request will be handled
// with an unmodified path, at the root of the bucket)

const remove_suffix = '.example.com';

// provide the correct origin hostname here so that we send the correct 
// Host header to the S3 website endpoint

const origin_hostname = 'example-bucket.s3-website-us-east-1.amazonaws.com';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;
    const host_header = headers.host[0].value;

    if(host_header.endsWith(remove_suffix))
    {
        // prepend '/' + the subdomain onto the existing request path ("uri")
        request.uri = '/' + host_header.substring(0,host_header.length - remove_suffix.length) + request.uri;
    }

    // fix the host header so that S3 understands the request
    headers.host[0].value = origin_hostname;

    // return control to CloudFront with the modified request
    return callback(null,request);
};

The above is an example I wrote and posted on the official AWS forum. It only works with the S3 web site hosting feature (not the REST endpoints) becauae this is required in order for the host header to be exposed to Lambda@Edge using the forwarded header whitelist.

It takes the prefix from the incoming hostname and rewrites it into a path prefix, while sending all requests to the same bucket.

Note that you will need a complementary function in an Origin Response trigger for handling responses, checking for HTTP 30x redirects. Because of the path prefixing we're doing, the opposite will need to be done on the reverse path, so that the Location header's path will be correctly anchored.

Or just create a single CloudFront distribution for each of your sites -- AWS doesn't charge for the distribution itself, only for the requests it handles. Distributions can be easily created through automation -- scripting with aws-cli, or CloudFormation. The default limit on CloudFront distributions per account is 200, but AWS Support will increase this on request.



来源:https://stackoverflow.com/questions/49472636/route-53-alias-dns-record-the-alias-target-name-does-not-lie-within-the-target

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!