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

Viewed 12678

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.

enter image description here

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.

7 Answers

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

enter image description here

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

screenshot

Related