Regional API Gateway with CloudFront - amazon-web-services

Amazon released new feature - to support regional api endpoints
Does it mean I can deploy my same API code in two regions which sends request to Lambda micro-services? (It will be two different Https endpoints)
And have CloudFront distribute the traffic for me?
Any code snippets?

Does it mean I can deploy my same API code in two regions which sends request to Lambda micro-services? (It will be two different Https endpoints)
This was already possible. You can already deploy the same API code in multiple regions and create different HTTPS endpoints using API Gateway.
What you couldn't do, before, was configure API Gateway API endpoints in different regions to expect the same hostname -- and this is a critical capability that was previously unavailable, if you wanted to have a geo-routing or failover scenario using API Gateway.
With the previous setup -- which has now been renamed "Edge-Optimized Endpoints" -- every API Gateway API had a regional endpoint hostname but was automatically provisioned behind CloudFront. Accessing your API from anywhere meant you were accessing it through the CloudFront, which meant optimized connections and transport from the API client -- anywhere on the globe -- back to your API's home region via the AWS Edge Network, which is the network that powers CloudFront, Route 53, and S3 Transfer Acceleration.
Overall, this was good, but in some cases, it can be better.
The new configuration offering, called a Regional API Endpoint, does not use CloudFront or the Edge Network... but your API is still only in one region (but keep reading).
Regional API Endpoints are advantageous in cases like these:
If your traffic is from EC2 within the region, this avoids the necessity of jumping onto the Edge Network and back off again, which will optimize performance of API requests from inside the same EC2 region.
If you wanted to deploy an API Gateway endpoint behind a CloudFront distribution that you control (for example, to avoid cross-origin complications, or otherwise integrate API Gateway into a larger site), this previously required that you point your CloudFront distribution to the CloudFront distribution managed by API Gateway, thus looping through CloudFront twice, which meant transport latency and some loss of flexibility.
Creating a Regional API Endpoint allows you to then point your own CloudFront distribution directly at the API endpoint.
If you have a single API in a single region, and it's being accessed from points all over the globe, and you aren't using CloudFront yourself, the Edge-Optimized endpoint is still almost certainly the best way to go.
But Regional API Endpoints get interesting when it comes to custom domain names. Creating APIs with the same custom domain name (e.g. api.example.com) in multiple AWS regions was not previously possible, because of API Gateway's dependency on CloudFront. CloudFront is a global service, so the hostname namespace is also global -- only one CloudFront distribution, worldwide, can respond to a specific incoming request hostname. Since Regional API Endpoints don't depend on CloudFront, provisioning APIs with the same custom domain name in multiple AWS regions becomes possible.
So, assuming you wanted to serve api.example.com out of both us-east-2 and us-west-2, you'd deploy your individual APIs and then in each region, create a custom domain name configuration in each region for api.example.com with a Regional API Endpoint, selecting an ACM certificate for each deployment. (This requires ACM certs in the same region as the API, rather than always in us-east-1.)
This gives you two different hostnames, one in each region, that you use for your DNS routing. They look like this:
d-aaaaaaaaaa.execute-api.us-east-2.amazonaws.com
d-bbbbbbbbbb.execute-api.us-west-2.amazonaws.com
So, what next?
You use Route 53 Latency-Based routing to create a CNAME record for api.example.com with two targets -- one from us-east-2, one from us-west-2 -- pointing to the two respective names, along with health checks on the targets. Route 53 will automatically resolve DNS queries to whichever regional endpoint is closer to the requester. If, for example, you try to reach the API from us-east-1, your DNS query goes to Route 53 and there's no record there for us-east-1, so Route 53 determines that us-east-2 is the closer of the two regions, and -- assuming the us-east-2 endpoint has passed its healthcheck -- Route 53 returns the DNS record pointing to d-aaaaaaaaaa.execute-api.us-east-2.amazonaws.com.
So, this feature creates the ability to deploy an API in multiple AWS regions that will respond to the same hostname, which is not possible with Edge Optimized API Endpoints (as all endpoints were, prior to the announcement of this new feature).
And have CloudFront distribute the traffic for me?
Not exactly. Or, at least, not directly. CloudFront doesn't make origin determinations based on the requester's region, but Lambda#Edge dynamic origin selection could be used to modify the origin server based on the requester's general location (by evaluating which API region is nearest to the CloudFront edge that happens to be serving a specific request).
However, as you can see, above, Route 53 Latency-Based routing can do that for you. Yet, there's still a compelling reason to put this configuration behind a CloudFront distribution, anyway... two reasons, actually...
This is in essence a DNS failover configuration, and that is notoriously unreliable when the access is being made by a browser or by a Java programmer who hasn't heard that Java seems to cache DNS lookups indefinitely. Browsers are bad about that, too. With CloudFront in front of your DNS failover configuration, you don't have to worry about clients caching your DNS lookup, because CloudFront does it correctly. The TTL of your Route 53 records -- which used as an origin server behind CloudFront -- behaves as expected, so regional failover occurs correctly.
The second reason to place this configuration behind CloudFront would be if you want the traffic to be transported on the Edge Network. If the requests are only coming from the two AWS regions where the APIs are hosted, this might not be helpful, but otherwise it should improve responsiveness overall.
Note that geo-redundancy across regions is not something that can be done entirely transparently with API Gateway in every scenario -- it depends on how you are using it. One problematic case that comes to mind would involve a setup where you require IAM authentication against the incoming requests. The X-Amz-Credential includes the target region, and the signature of course would differ because the signing keys in Signature V4 are based on the secret/date/region/service/signing-key paradigm (which is a brilliant design, but I digress). This would complicate the setup since the caller would not know the target region. There may be other complications. Cognito may have similar complications. But for a straightforward API where the authentication is done by your own mechanism of application tokens, cookies, etc., this new capability is very much a big deal.
Somewhat amusingly, before this new capability was announced, I was actually working on the design of a managed service that would handle failover and geo-routing of requests to redundant deployments of API Gateway across regions, including a mechanism that had the capability to compensate for the differing region required in the signature. The future prospects of what I was working on are a bit less clear at the moment.

It means you can deploy your API based on the region which reduces latency.
One use case would be, Say you have a Lambda function which is invoking an API request. If both Lambda and API is in the same region then you can expect high performance
Please have a look on https://docs.aws.amazon.com/apigateway/latest/developerguide/create-regional-api.html

Related

AWS: what's the point in using CloudFront for API requests instead of routing them to ALB directly?

I have a load balancer (ALB) that is dealing with my app's API requests (alb.domain.com) . I also have an S3 bucket where my static site is served from via CloudFront (domain.com). I have configured a distribution so that /api goes to the ALB and the rest goes to S3 and all works fine. However, instead of routing my API requests to CloudFront (domain.com/api), I can also route them directly to the ALB (alb.domain.com/api), which also works fine. I don't need caching on my API requests so i disabled it on the distribution anyway. What would be the point in me doing the requests via CloudFront given that I am (1) introducing an extra connection in the route and (2) my requests are now calculated for CloudFront pricing. Are there any disadvantages associated with just routing requests directly to the ALB and using CloudFront only for serving static files?
There are a number of benefits to using CloudFront in your scenario (and generally).
Firstly by having route through CloudFront it gives the impression this is a single domain, this removes implementation of CORS, helps to reduce complexities in any security configurations (such as CSP). Additionally you can cache any static based requests, or those that change infrequently in the future if you need it.
You also gain the benefits that you get access to the edge network to do routing, this benefits for clients that are further away from the region. This means that the user will hit the closest edge location to them, which will then route and establish a connection with the origin over the private AWS network (which will be faster than traversing the public internet).
Additionally security evaluations at the Edge, both WAF and Lambda#Edge can be evaluated closer to the user on AWS Edge infrastructure rather than your own resources.

Multiple region deployment with Geolocation based policy v/s Cloudfront

I have a custom origin i.e. a web app on an EC2 instance. How do I decide whether I should go for:
a Cloudfront CDN
or,
deploy multiple instances in different regions and configure a Geolocation/proximity based routing policy
The confusion arises from the fact that both aim at routing the request to the nearest location (edge location in case of Cloudfront and region specific EC2 instance when it comes to multi-region deployments with Geolocation based policy with Route 53) based on where the request originates from.
There is no reason why you can't do both.
CloudFront automatically routes requests to an edge location nearest the viewer, and when a request can't be served from that location or the nearest regional cache, CloudFront does a DNS lookup for the origin domain name and fetches the content from the origin.
So far, I've only really stated the obvious. But up next is a subtle but important detail:
CloudFront does that origin server DNS lookup from a location that is near the viewer -- which means that if the origin domain name is a latency-based record set in Route 53, pointing to deployments in two or more EC2 regions, then the request CloudFront makes to "find" the origin will be routed to the origin deployment nearest the edge, which is also by definition going to be near to the viewer.
So a single, global CloudFront deployment can automatically and transparently select the best origin, using latency-based configuration for the backend's DNS configuration.
If the caching and transport optimizations provided by CloudFront do not give you the global performance you require, then you can deploy in multiple regions, behind CloudFront... being mindful, always, that a multi-region deployment is almost always a more complex environment, depending on the databases that are backing your application and how they are equipped to handle cross-region replication for reads and/or writes.
Including CloudFront as the front-end is also a better solution for fault tolerance among multiple regional deployments, because CloudFront correctly honors the DNS TTL on your origin server's DNS record, and if you have Route 53 health checks configured to take an unhealthy region out of the DNS response on the origin domain name, CloudFront will quickly stop sending further requests to it. Browsers are notoriously untrustworthy in this regard, sometimes caching a DNS answer until all tabs/windows are closed.
And if CloudFront is your front-end, you can offload portions of your logic to Lambda#Edge if desired.
You can use multi region for lot reasons mainly,
Proximity
Failover (incase if first region fails, requests can be sent to another region)
Multi region lambda deployment is clearly documented here. You can apply the same logic to all of the AWS Resources too. (DynamoDB, S3)
https://aws.amazon.com/blogs/compute/building-a-multi-region-serverless-application-with-amazon-api-gateway-and-aws-lambda/
You can also run Lambda#Edge to force all your requests / splits to one region on the edge.
Hope it helps.

AWS architecture - Web application (Diagram)

I am in the process of setting up a medium sized AWS infrastructure for a web project. I may be overthinking a couple things and therefore wanted to ask the community for opinions. Any input is appreciated.
Please see the graphic:
here
Explanation (from left to right):
My domain is hosted on GoDaddy and will simply route to Cloudfront in order to globally cache static content.
Cloudfront will point to Route53 which is responsible for routing the user to the closest region based on Geoprximity and/or Latency
Each region will have an availability load balancer pointing to an EC2 instance (different availability zones for disasters fallback)
From there, each EC2 instance writes to a single MySQL database. Static content is loaded from a S3 bucket.
This MySQL database replicates/synchronizes itself across availability zones and regions and creates read-replicas
If an EC2 instance has a read-request, it contacts another Route53 router that forwards the read-request to a load-balancer (in each region) based on where the request is coming from (geoproximity/latency). The only alternative I see here would be to directly point read-requests from a European EC2 instance to a European load-balancer. (vice versa for US)
The load-balancer in each region will then decide from which database to read based on health or amount of requests
Each EC2 instance can also trigger a LAMBDA function through an API Gateway.
What am I missing? Is this too much? What are the ups and downs of this construct?
Thank you all so much!
Things look reasonable up to step 6. There's no need to find the nearest MySQL database, because your instances already know where it is -- it's the one in the local region.
Step 7 is problematic because ELBs can't be used to balance RDS instances. However, with Aurora/MySQL, you get a single cluster "reader" endpoint hostname with a short TTL that load balances across your Aurora replicas. If a replica dies, it's removed from DNS automatically.
Step 8 it's not strictly necessary to use API Gateway -- instances can directly invoke Lambda functions through the Lambda API.
Additionally, there's Lambda#Edge that allows triggering Lambda functions directly from CloudFront -- although if the Lambda function you need is large in size (dependencies) or needs to run inside a VPC, you have to cascade two of them -- the edge function (not in VPC) invokes the regional function (large, or in a VPC) -- but this is still typically less expensive than API Gateway. Edge functions automatically replicate globally and run in the region closest to the CloudFront edge handling the individual request, and within any given function invocation this can be identified by inspecting process.env.AWS_REGION. Edge functions can also be used to change the origin serving the content -- so, e.g. if your function sees that it's been invoked in an EU region, it can rewrite the request so that CloudFront will send S3 requests to an EU bucket.
If your site is at the apex of a domain, e.g. example.com rather than, say, www.example.com, your domain will need to be hosted in Route 53, not Go Daddy, because constraints in the DNS standards do not allow the dynamic behavior required by CloudFront at the apex. You can still have your domain registered with them, but not hosted by them.

Are route53 failover policy records only useful for non aws alias-able resources?

If all my endpoints are AWS services like ELB or S3 "Evaluate Target Health" can be used instead of failover records correct? I can use multiple weighted, geo, or latency records and if I enabled "Evaluate Target Health" it also servers the purpose of failover if one of the resources a record is pointing to is not healthly route53 will not send traffic to it.
The only use I see for failover records with custom healthchecks is for non-aws resources OR if maybe you have a more complex decision you want DNS to make instead of just ELB/S3/etc service health.
EDIT: so it seems while I can get active-active with "Evaluate Target Health" (on alias endpoints) if I want active-passive I have to use a failover policy- is this correct?
Essentially, yes. Evaluating target health makes the records viable candidates for generating responses, only when healthy. Without a failover policy, they're all viable when they're all healthy.
If you do something like latency-based routing and you had two targets, let's say Ohio and London, then you'd essentially have a dual active/passive configuration with reversed roles -- Ohio active and London passive for viewers in North America, and the roles reversed for viewers in Europe. But if you want global active/passive, you'd need a a failover policy.
Note that if you are configuring any kind of high-availability design using Route 53 and target health, your best bet is to do all of this behind CloudFront -- where the viewer always connects to CloudFront and CloudFront does the DNS lookup against Route 53 to find the correct origin based on whatever rules you've created. The reason for this is that CloudFront always respects the DNS TTL values. Browsers, for performance reasons, do not. Your viewers can find themselves stuck with DNS records for a dead target because their browsers don't flush their cached DNS lookups until all tabs in all windows are closed. For users like me, that almost never happens.
This also works with latency-based routes in Route 53 behind CloudFront, because CloudFront has already routed the viewer to its optimal edge, and when that edge does a lookup on a latency-based route in Route 53, it receives the answer that has the lowest latency from the CloudFront edge that's handling the request... so both viewer to CloudFront and CloudFront to origin routes are thus optimal.
Note also that failover routing to S3 with only DNS is not possible, because S3 expects the hostname to match the bucket name, and bucket names are global. An S3 failure is a rare event, but it has happened at least once. When it happened, the impact was limited to a single region, as designed. For a site to survive an S3 regional failure requires additional heroics involving either CloudFront and Lambda#Edge triggers, or EC2-based proxies that can modify the request as needed and send it to the alternate bucket in an alternate region.
Latency-based routing to buckets with Route 53 is also not possible, for the same reason, but can be accomplished by Lambda#Edge origin request triggers. These triggers are aware of the AWS region where a given invocation is running, and thus can swap origin servers based on location.

Regional/Edge-optimized API Gateway VS Regional/Edge-optimized custom domain name

This does not make sense to me at all. When you create a new API Gateway you can specify whether it should be regional or edge-optimized. But then again, when you are creating a custom domain name for API Gateway, you can choose between the two.
Worst of all, you can mix and match them!!! You can have a regional custom domain name for an edge-optimized API gateway and it's absolutely meaningless to me!
Why these two can be regional/edge-optimized separately? And when do I want each of them to be regional/edge-optimized?
Why these two can be regional/edge-optimized separately?
Regional and Edge-Optimized are deployment options. Neither option changes anything fundamental about how the API is processed by the AWS infrastructure once the request arrives at the core of the API Gateway service or how the services behind API Gateway ultimately are accessed -- what changes is how the requests initially arrive at AWS and are delivered to the API Gateway core for execution. More about this, below.
When you use a custom domain name, your selected API stage is deployed a second time, on a second endpoint, which is why you have a second selection of a deployment type that must be made.
Each endpoint has the characteristics of its deployment type, whether regional or edge-optimized. The original deployment type of the API itself does not impact the behavior of the API if deployed with a custom domain name, and subsequently accessed using that custom domain name -- they're independent.
Typically, if you deploy your API with a custom domain name, you wouldn't continue to use the deployment endpoint created for the main API (e.g. xxxx.execute-api.{region}.amazonaws.com), so the initial selection should not matter.
And when do I want each of them to be regional/edge-optimized?
If you're using a custom domain name, then, as noted above, your original deployment selection for the API as a whole has no further impact when you use the custom domain.
Edge-optimized endpoints were originally the only option available. If you don't have anything on which to base your selection, this choice is usually a reasonable one.
This option routes incoming requests through the AWS "Edge Network," which is the CloudFront network, with its 100+ global edge locations. This does not change where the API Gateway core ultimately handles your requests -- they are still ultimately handled within the same region -- but the requests are routed from all over the world into the nearest AWS edge, and they travel from there on networks operated by AWS to arrive at the region where you deployed your API.
If the clients of your API Gateway stage are globally dispersed, and you are only deploying your API in a single region, you probably want an edge-optimized deployment.
The edge-optimized configuration tends to give you better global responsiveness, since it tends to reduce the impact of network round trips, and the quality of the transport is not subject to as many of the vagaries of the public Internet because the request covers the least amount of distance possible before jumping off the Internet and onto the AWS network. The TCP handshake and TLS are negotiated with the connecting browser/client across a short distance (from the client to the edge) and the edge network maintains keep-alive connections that can be reused, all of which usually works in your favor... but this optimization becomes a relative impairment when your clients are always (or usually) calling the API from within the AWS infrastructure, within the same region, since the requests need to hop over to the edge network and then back into the core regional network.
If the clients of your API Gateway stage are inside AWS and within the same region where you deployed the API (such as when the API is being called by other systems in EC2 within the region), then you will most likely want a regional endpoint. Regional endpoints route requests through less of the AWS infrastructure, ensuring minimal latency and reduced jitter when requests are coming from EC2 within the same region.
As a side-effect of routing through the edge network, edge-optimized endpoints also provide some additional request headers that you may find useful, such as CloudFront-Viewer-Country: XX which attempts to identify the two-digit country code of the geographic location of the client making the API request. Regional endpoints don't have these headers.
As a general rule, go with edge-optimized unless you find a reason not to.
What would be some reasons not to? As mentioned above, if you or others are calling the API from within the same AWS region, you probably want a regional endpoint. Edge-optimized endpoints can introduce some edge-case side-effects in more advanced or complicated configurations, because of the way they integrate into the rest of the infrastructure. There are some things you can't do with an edge-optimized deployment, or that are not optimal if you do:
if you are using CloudFront for other sites, unrelated to API Gateway, and CloudFront is configured for a wildcard alternate domain name, like *.example.com, then you can't use a subdomain from that wildcard domain, such as api.example.com, on an edge-optimized endpoint with a custom domain name, because API Gateway submits a request to the edge network on your behalf to claim all requests for that subdomain when they arrive via CloudFront, and CloudFront rejects this request since it represents an unsupported configuration when used with API Gateway, even though CloudFront supports it in some other circumstances.
if you want to provide redundant APIs that respond to the same custom domain name in multiple regions, and use Route 53 Latency-Based Routing to deliver requests to the region nearest to the requester, you can't do this with an edge-optimized custom domain, because the second API Gateway region will not be able to claim the traffic for that subdomain on the edge network, since the edge network requires exactly 1 target for any given domain name (subdomain). This configuration can be achieved using regional endpoints and Route 53 LBR, or can be achieved while leveraging the edge network by using your own CloudFront distribution, Lambda#Edge to select the target endpoint based on the caller's location, and API Gateway regional deployments. Note that this can't be achieved by any means if you need to support IAM authentication of the caller, because the caller needs to know the target region before signing and submitting the request.
if you want to use your API as part of a larger site that integrates multiple resources, is deployed behind CloudFront, and uses the path to route to different services -- for example, /images/* might route to an S3 bucket, /api/* might route to your API Gateway stage, and * (everything else) might route to an elastic load balancer in EC2 -- then you don't want to use an edge-optimized API, because this causes your requests to loop through the edge network twice (increasing latency) and causes some header values to be lost. This configuration doesn't break, but it isn't optimal. For this, a regional endpoint is desirable.