I am having cname(abc.com) pointed to my elastic IP and need to create three EC2 instances(e.g. Instance1, Instance2, Instance3) for three different applications.
Now I want to achieve following results:
If user hits "abc.com/App1", request should be redirected to Instance1.If user hits "abc.com/App2", request should be redirected to Instance2.If user hits "abc.com/App3", request should be redirected to Instance3.
All these Instances should work independently. And, If any of these goes down, it should not impact others.
We can't use subdomains. I am trying to find out something in ELB.
ELB does not offer path-based routing. All instances connected to an ELB receive a share of incoming requests.
CloudFront, however, does support path-based routing. You can configure each instance as a "custom origin" and configure which path patterns to route to it.
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesPathPattern
Granted, this is not the "primary purpose" of CloudFront, but it works quite nicely in this application.
CloudFront is actually a caching reverse proxy CDN service, so if you go this route, you can also potentially relieve your back-end machines of some workload, or you can disable caching entirely by forwarding all the request headers to the origin and returning an appropriate Cache-Control: header from your instances.
A CloudFront distribution can be associated with a domain name in Route 53 in exactly the same way that an ELB can -- using Alias records.
Bonus: you can also easily pluck additional paths and route them directly to S3 to serve up static assets from an S3 bucket.
Related
My S3(front-end codes), and EC2(back-end codes) are BOTH linked to 'example.com'
What I like to do here is to direct users to view the pages, stored in S3, unless they input 'example.com/api/'on their browser.
In other words, 'example.com/api/' for the server access, and the other routes for the react app access.
which service should I use in AWS? CloudFront, Route53, Load Balance. I am so confused. thank you.
TLDR; Create a single CloudFront distribution for your domain with separate cache behaviors for each of the paths you need to support. You can easily add additional applications, control caching, or write edge functions (using Lambda#Edge or CloudFront Functions) for any further customization you might need.
Details: CloudFront allows you to configure multiple origins (e.g. S3, EC2, API Gateway, ELB, custom URLs, and so forth) and then create cache behaviors (routes) that direct traffic to the appropriate origin.
In your case, you would create a cache behavior of /api/* to point to your EC2 origin, and the default cache behavior (think of this as your fallback route) would point to your S3 origin for all requests that do not begin with /api/
You can create a subdomain say api.example.com using Route53, here is a document for that https://aws.amazon.com/premiumsupport/knowledge-center/create-subdomain-route-53/
And for routing traffic for the newly created subdomain go through this document https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-routing-traffic-for-subdomains.html
So currently we have two ec2 instances (lets say A and B) and a cloudfront.
If the user goes to www.appdomain.com/app the user should get routed to the cloudfront SPA page. However if the user goes www.appdomain.com the user should be routed to the EC2 instance A, and if user goes to www.appdomain.com/api be routed to EC2 instance B.
All of these applications must be on the same domain.
Now we found out how to set path rules using an application load balancer, but would like to know how to set it to cloudfront as well.
Update:
So in summary the question is how do we route /app to cloudfront / and /api to ec2.
All of these applications must be on the same domain.
In this scenario, every request for that domain must pass through CloudFront first.
Your DNS record will need to point to CloudFront (not the ALB) and CloudFront is then responsible for routing the request to the appropriate target -- to an EC2 instance via an ALB, to an S3 bucket, to wherever you need the requests to go -- and each of these things is called a content origin.
Once the origins are specified by their individual domain name (not your site's domain name, but a domain name specifically for the resource in question), you define CloudFront path patterns to select which origin is to receive the request for each pattern (e.g. /api*).
Once your DNS is changed to point to CloudFront, all requests go there first, and are handed off to the next service, unless CloudFront has a cached copy of the requested object -- in which case, CloudFront will serve it from its cache, and nothing will be sent to the origin.
You can't route from ALB to CloudFront, but you can route from CloudFront to ALB.
You can't subdivide a domain into multiple, different path-based content origins without using a reverse proxy that is able to match the paths and fetch the content on behalf of the requester -- HTTP and DNS don't support such functionality. CloudFront, in addition to providing the CDN service, is also a reverse proxy.
ALB, of course, is also a reverse proxy, but does not support as many different types of content origins as CloudFront does -- ALB only supports EC2 instances, servers in your data center (in which case, ALB must have a VPN path in order to reach them), and Lambda functions as content origins. CloudFront can use literally anything as a content origin as long as it speaks HTTP/HTTPS and is accessible via the Internet. (To choose a somewhat random example, CloudFront can even use a service from another vendor -- like a Google Cloud Storage bucket -- as a content origin, if that was something you needed to do, for whatever reason... because these are accessible via HTTP across the public Internet.)
We have static html pages hosted on S3, which talk to REST services hosted on EC2 (managed by Elastic Beanstalk). Because S3 and EB are different hosts, these are CORS requests. The backend server is setting the required headers to allow CORS:
if(allowOrigin){
response.setHeader("Access-Control-Allow-Origin", clientOrigin);
response.setHeader("Access-Control-Allow-Credentials", "true");
}
The problem is that the REST services use sessions, which means they send a session cookie back to the browser. But most browsers have "don't accept 3rd party cookies" by default, so this doesn't actually work. We could pass the value of the session cookie as a POST parameter, but then we'd have to re-implement session management that JEE does for us a with a simple call to request.getSession(true).
As a solution, we are hoping for some DNS wizardry that would allow us to present both S3 and EB services as if they are the same domain. So for example, do something like this:
Request: mydomain.com/somePath/to/page --> redirect to S3 bucket/somePath/to/page
Request: mydomain.com/services/path/to/service --> redirect to EB/path/to/service
So the redirect is conditional to /services/ being present as the root folder
We'd prefer to do this at the DNS level rather than from within an S3 redirect, because Amazon charges fees for every request that hits S3 (so we'd be paying twice for all hits to /services/
How can we achieve something like that? Other ideas welcome.
You can do this with CloudFront.
Create a distribution on CloudFront for your "common" domain. All requests will go through CloudFront.
Create two origins in your distribution:
One origin that will use your S3 bucket, and
One origin that will use your EB application
You can then separate these origins based on the HTTP request path using 2 behaviours.
You'll also be able to take advantage of CloudFront's ability to cache your static S3 assets.
CNAME entries, perhaps?
If I've got A.example.com as a CNAME to myhost.example1.net (or whatever), and B.example.com as a CNAME to myotherhost.example2.net (or whatever), then a web browser visiting A.example.com, if that page has a reference to B.example.com, sees them as being from A.example.com and B.example.com, regardless of where they're actually hosted.
I've got a lot of field servers where I do something like this. At the locations where I've got a static IP addresses, I've got A records for them on my primary domain range. At the locations where I don't, I've got CNAME records for them on my primary domain range, which point at Dynamic DNS records via a different provider.
How does cloudfront work with Route53 routing policies?
So as I understand it CF is supposed to route requests to the nearest server, which is in effect the Route53 latency policy. So if you have an R53 hosted zone entry for your CF domain name is this done by default if you leave the routing policy as simple or do you neec to explicitly set this yourself? And if you chose another policy type (failover, geo-location etc) would that overwrite it?
You leave it as simple.
You don't have access to the necessary information to actually configure it yourself -- CloudFront returns an appropriate DNS response based on the location of the requester, from a single, simple DNS record. The functionality and configuration is managed transparently by the logic that powers the cloudfront.net domain, you set it and forget it, because there are no user-serviceable parts inside.
This is true whether you use an A-record Alias or a CNAME.
Any other configuration would not really make sense, because talking of failover or geolocation imply that you'd want to send traffic somewhere other than where CloudFront's algorithm would send it.
Now... there are cases when, behind CloudFront, you might want to use some of Route 53's snazzier options. Let's say you had app servers in multiple regions serving exactly the same content. Latency-based routing for the origin hostname (the one where CloudFront sends cache misses) would allow CloudFront to magically send requests to the app server closest to the CloudFront edge that serves each individual request. This would be unrelated to the routing from the browser to the edge, though.
I am hosting my website using AWS.
The website is on 2 ec2 instances, with a load balancer (ELB) balancing traffic between them.
Currently, I am using my DNS (Route 53) to restrict the access to the website by using Route 53's geolocation routing:
http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html#routing-policy-geo
(The geolocation restriction is just to limit the initial release of my website. It is not for security reasons. Meaning the restriction just needs to work for the general public)
This worries me a little because my load balancer is still exposed to access from everywhere. So I am concerned that my load balancer will get indexed by google or something and then people outside of my region will be able to access the site.
Are there any fixes for this? Am I restricting access by location the wrong way? Is there a way perhaps to specify in the ELB's security group that it only receive inbound traffic from my DNS (of course then I would also have to specify that inbound traffic from edge locations be allowed as well for my static content but this is not a problem)?
Note: There is an option when selecting inbound rules for a security group, under "type" to select "DNS(UDP)" or "DNS(TCP)". I tried adding two rules for both DNS types (and IP Address="anywhere") for my ELB but this did not limit access to the ELB to be solely through my DNS.
Thank you.
The simple solution, here, is found in CloudFront. Two solutions, actually:
CloudFront can use its GeoIP database to do the blocking for you...
When a user requests your content, CloudFront typically serves the requested content regardless of where the user is located. If you need to prevent users in specific countries from accessing your content, you can use the CloudFront geo restriction feature[...]
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/georestrictions.html
You can configure CloudFront with which countries are allowed, or which are denied. You can also configure static pages, stored in S3, which are displayed to denied users. (You can also configure static custom error pages for other CloudFront errors that might occur, and store those pages in S3 as well, where CloudFront will fetch them if it ever needs them).
...or...
CloudFront can pass the location information back to your server using the CloudFront-Viewer-Country: header, and your application code, based on the contents accompanying that header, can do the blocking. The incoming request looks something like this (some headers munged or removed for clarity):
GET / HTTP/1.1
Host: example.com
X-Amz-Cf-Id: 3fkkTxKhNxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
Via: 1.1 cb76b079000000000000000000000000.cloudfront.net (CloudFront)
CloudFront-Viewer-Country: US
CloudFront-Forwarded-Proto: https
Accept-Encoding: gzip
CloudFront caches the responses against the combination of the requested page and the viewer's country, and any other whitelisted headers, so it will correctly cache your denied responses as well as your allowed responses, independently.
Here's more about how you enable the CloudFront-Viewer-Country: header:
If you want CloudFront to cache different versions of your objects based on the country that the request came from, configure CloudFront to forward the CloudFront-Viewer-Country header to your origin. CloudFront automatically converts the IP address that the request came from into a two-letter country code.
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-location
Or, of course, you can enable both features, letting CloudFront do the blocking, while still giving your app a heads-up on the country codes for the locations that were allowed through.
But how do you solve the issue with the fact that your load balancer is still open to the world?
CloudFront has recently solved this one, too, with Custom Origin Headers. These are secret custom headers sent to your origin server, by CloudFront, with each request.
You can identify the requests that are forwarded to your custom origin by CloudFront. This is useful if you want to know whether users are bypassing CloudFront[...]
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/forward-custom-headers.html
So, let's say you added a custom header to CloudFront:
X-Yes-This-Request-Is-Legit: TE9MIHdoYXQgd2VyZSB5b3UgZXhwZWN0aW5nIHRvIHNlZT8=
What's all that line noise? Nothing, really, just a made up secret value that only your server and CloudFront know about. Configure your web server so that if this header and value are not present in the incoming request, then access is denied -- this is a request that didn't pass through CloudFront.
Don't use the above secret, of course... make up your own. It's entirely arbitrary.
Caveat applicable to any GeoIP-restricting strategy: it isn't perfect. CloudFront claims 99.8% accuracy.
The most reliable way to implement geographic IP restrictions, is to use a geographic location database or service API, and implement it at the application level.
For example, for a web site in practically any language, it is very simple to add test at the start of each page request, and compare the client IP against the geo ip database or service, and handle the response from there.
At the application level, it is easier to manage the countries you accept/deny, and log those events, as needed, than at the network level.
IP based geo location data is generally reliable, and there are many sources for this data. While you may trust AWS for many things, I do think that there are many reliable 3rd party sources for geo IP dat, that focus on this data.
freegeoip.net provides a public HTTP API to search the geolocation of IP addresses. You're allowed up to 10,000 queries per hour.
ip2location.com LITE is a free IP geolocation database for personal or commercial use.
If your application uses a database, these geo databases are quite easy to import and reference in your app.
I have a post explaining in detail how to whitelist / blacklist locations with Route53: https://www.devpanda.me/2017/10/07/DNS-Blacklist-of-locations-countries-using-AWS-Route53/.
In terms of your ELB being exposed to public that shouldn't be a problem since the Host header on any requests to the ELB over port 80 / 443 won't match your domain name, which means for most web servers a 404 will be returned or similar.
There is a way using AWS WAF
You can select - Resource type to associate with web ACL as ELB.
Select your ELB and create conditions like Geo Match, IP Address etcetera.
You can also update anytime if anything changes in future.
Thanks