Absolute path of cloudfront while displacing custom error pages - amazon-web-services

I have an application which reside on EC2 instance, traffic comes from cloudfront--->ALB---->EC2 instance. If anyone is access the wrong url, the application throw an error page depending on the error.
Suppose, if I type a wrong url (abc.com/test/index.html) it will redirect to abc.com/error/404 (This is manage through application itself).
If, EC2 instance is down the error page are display through cloudfront using custom error page. But the problem here is, when I type the wrong url (abc.com/test/index.html) it will display the error page of 404 but will not change the url to abc.com/error/404 .
Also, the error page display through S3 bucket. Can anyone suggest any option to set this up in cloudfront.

Based on what you wrote, I suppose you're using ReactJS or similar since you're handling error pages in your application.
In order to do that in the ReactJS application, you need to add custom error responses for 403 and 404 codes.
For both of these, you need to set ResponseCode to 200 and ResponsePagePath to "/index.html" (since index.html is what's doing the routing in your application)

Related

Can an angular app on AWS S3 served via cloudfront resolve to another route apart from the index route?

I have an angular app hosted on S3. When I try to directly go to a route like myapp.com/items I get a 403 forbidden error. But when I access the app from myapp.com everything is okay and from the app I can navigate to myapp.com/items. I don't understand why this is happening.
How can I make it so that routes like myapp.com/items can be accessed directly and not throw an error?
On CloudFront distribution enter error pages tab
Then create a new error response to deal with any othe routes and redirect it to index.html file

AWS CloudFront + Lambda#Edge "The JSON output is not parsable"

I have a Lambda function (a packaged next.js app) which I'm trying to access via CloudFront. The web app works unless I try to hit the homepage.
When I hit /search or /video/{videoId} the page loads just fine.
When I try to hit the homepage, I get the following error page:
502 ERROR
The request could not be satisfied.
The Lambda function returned invalid JSON: The JSON output is not parsable. We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
Generated by cloudfront (CloudFront)
Request ID: {id}
Why would just the homepage be invalid JSON? Where can I see this JSON to determine what is wrong? I created a mock Cloudfront request test in the Lambda function and it just returns successfully.
The problem was due to the 1 MB size limit of CloudFront Lambda#Edge responses. I didn't realize that Next.js's serverside rendering was creating a large <script id="__NEXT_DATA__"> tag on my homepage with all the fetched info from my API duplicated multiple times over. This resulted in my app's homepage being >2 MB.
I refactored my app to only send one network request, and made sure that data is only put into the __NEXT_DATA__ tag once. The app now works.

Invoking a Lambda through API-Gateway giving 403 response?

I am using AWS codestar to deploy by react application using serverless nodejs template. This is the url that is given by codestar after successfully completion of all the stages https://xxxxx.execute-api.us-east-1.amazonaws.com/Prod . This url displayed all the components in my app correctly. In navbar of my app i have items like this a ,b,c. where clicking on each one of them will redirect to a new component.(i.e.https://xxxxx.execute-api.us-east-1.amazonaws.com/a,https://xxxxx.execute-api.us-east-1.amazonaws.com/b etc. But when i refresh the page which is having a url like this https://xxxxx.execute-api.us-east-1.amazonaws.com/b i am getting a error like {"message":"Forbidden"} and in my console it is showing like this favicon.ico:1 GET https://xxxx.execute-api.us-east-1.amazonaws.com/favicon.ico 403
It seems the chrome is fetching the favicon based on the https link, which fails because there is no such favicon at the location. I tried to remove favicon.ico link in index.html but even then the chrome is using the same url to fetch the favicon which eventually fails. I followed max number of suggestions in SO to acheive this but no luck. Is there any way to say api-gateway to exclude these favicon get requests and display my app rather than showing message forbidden.
And i am pretty sure that i had enabled logs for both the agi-gateway and lambda where i didnt find any forbidden errors(i.e.403) which is weird because i can see those 403 errors in my console.
Thanks
Any help is highly appreciated.
The https://xxxxx.execute-api.us-east-1.amazonaws.com/Prod url provided by API Gateway is the base url for your site, so those paths would have to be /Prod/a instead of /a.
One way to get around that is to register your own domain and connect it to API Gateway via a custom domain. That would allow you to have https://example.com as your base url, and your paths could stay /a, /b, etc.

Receive AccessDenied when trying to access a page via the full url on my website

For a while, I was simply storing the contents of my website in a s3 bucket and could access all pages via the full url just fine. I wanted to make my website more secure by adding an SSL so I created a CloudFront Distribution to point to my s3 bucket.
The site will load just fine, but if the user tries to refresh the page or if they try to access a page using the full url (i.e., www.example.com/home), they will receive an AccessDenied page.
I have a policy on my s3 bucket that restricts access to only the Origin Access Identity and index.html is set as my domain root object.
I am not understanding what I am missing.
To demo, feel free to visit my site.
You will notice how it redirects you to kurtking.me/home. To reproduce the error, try refreshing the page or access a page via full URL (i.e., kurtking.me/life)
Any help is much appreciated as I have been trying to wrap my head around this and search for answers for a few days now.
I have figured it out and wanted to post my solution in case anyone else runs into this issue.
The issue was due to Angular being a SPA (Single Page App) and me using an S3 bucket to store it. When you try to go to a specific page via url access, CloudFront will take (for example, /about) and go to your S3 bucket looking for that file. Because Angular is a SPA, that file doesn't technically exist in your S3 bucket. This is why I was getting the error.
What I needed to do to fix it
If you open your distribution in Cloudfront, you will see an 'Error Pages' tab. I had to add two 'Custom Error Responses' that handled 400 and 403. The details are the same for 400 and 403, so I only include a photo for 400. See below:
Basically, what is happening is you are telling Cloudfront that regardless of a 400 or 403 error, to redirect back to index.html, thus giving control to Angular to decide if it can go to the path or not. If you would like to serve the client a 400 or 403 error, you need to define these routes in Angular.
After setting up the two custom error responses, I deployed my cloudfront solutions and wallah, it worked!
I used the following article to help guide me to this solution.
The better way to solve this is to allow list bucket permission and add a 404 error custom rule for cloudfront to point to index.html. 403 errors are also returned by WAF, and will cause additional security headaches, if they are added for custom error handling to index.html. Hence, better to avoid getting 403 errors from S3 in the first place for angular apps.
If you have this problem using CDK you need to add this :
MyAmplifyApp.addCustomRule({
source: '</^[^.]+$|\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>',
target: '/index.html',
status: amplify.RedirectStatus.REWRITE
});
The accepted answer seems to work but it does not seem like a good practice. Instead check if the cloudfront origin is set to S3 Bucket(in which the static files are) or the actual s3 url endpoint. It should be the s3 url endpoint and not the s3 bucket.
The url after endpoint should be the origin
Add a Cloudfront function to rewrite the requested uri to /index.html if it doesn't match a regex.
For example, if none of your SPA routes contain a "." (dot), you could do something like this:
function handler(event) {
var request = event.request
if (/^(?!.*\..*).*$/.test(request.uri)) {
request.uri = '/index.html'
}
return request
}
This gets around any kind of side effects you would get by redirecting 403 -> index.html. For example, if you use a WAF to restrict access by IP address, if you try to navigate to the website from a "bad IP", a 403 will be thrown, but with the previously suggested 403 -> index.html redirect, you'd still see index.html. With a cloudfront function, you wont.
For those who are trying to achieve this using terraform, you only need to add this to your CloudFront Configuration:
resource "aws_cloudfront_distribution" "cf" {
...
custom_error_response {
error_code = 403
response_code = 200
response_page_path = "/index.html"
}
...
}
Please check from the console which error are you getting. In my case I was getting a 403 forbidden error, and using the settings which are shown in the screenshot worked for me

How to get the requested path on custom error page with cloudfront

I'm using a cloudfront distribution with a custom origin for error processing, well I need to know how to get the requested path in my error page.
when "foo/file.htm" is requested a 404 Not Found Error is catched and the "error404.php" page is called in my server, well, I need to know the path that rises the error for building the response page and write "the file 'foo/file.htm' is not found" or something like that.
You can easily do this with some JavaScript on your custom error page. I would take a look at How to get request uri from location.href in javascript?.
I think that would be a Dynamic Web Application's WebPage which you need to link it with the Error Page.
In the Dynamic Web Application's webpage you need to get the query path from the domain of the incoming request and return back a new dynamic response back.
The extra care you need to take from your side is that, CloudFront may cache the page; so ensure you set the cache expiry settings appropriately.
Example :
You get a request foo.html which not is your distribution, the CloudFront will talk to your origin server and get the new dynamic page like [ Sorry you have reached the wrong Page - foo.html ].
The next time similarly when you get a request for bar.html which also not in your distribution, ensure the CloudFront talk to your origin server again and get the new page, if not even for the current request you might get the old error message [ Sorry you have reached the wrong Page - foo.html ] instead of the bar.html