Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS Cognito - Restrict Parts of Static S3 Website to Logged in Users

I'm building a small static website that I have hosted on s3. I used Cognito to get some basic user verification up and running (login, logout). I want to restrict certain parts of the website to only logged in users.

I worked through module 2 of this workshop https://github.com/aws-samples/aws-serverless-workshops/tree/master/WebApplication. In this workshop, the page /rides.html is restricted to logged in users. If you are not logged in and try to access /rides.html, the page will start to load, and then quickly redirect you to /signin.html. The trouble with this is that unauthorized users can still see the rides page for a split second before redirection occurs.

Here is their code that handles redirecting a user who hasn't logged in. It is run as javascript when a user tries to access /rides.html

   WildRydes.authToken.then(function setAuthToken(token) {
       if (token) {
           authToken = token;
       } else {
           window.location.href = '/signin.html';
       }
   }).catch(function handleTokenError(error) {
       alert(error);
       window.location.href = '/signin.html';
   });

I am having a lot of trouble determining the best way to ensure only users who have signed in can access parts of my website. Very new to anything webdev/AWS related, and I'm having some trouble finding this information online.

Edit: To clear up what I want to achieve - I want the entire rides.html page to be inaccessible to anyone who hasn't logged in.

Solution: We ended up putting a restricted CloudFront in front of the s3 bucket. Then, we had a lambda triggered when someone tried to access the CloudFront. Here is a tutorial: https://douglasduhaime.com/posts/s3-lambda-auth.html

like image 728
kjmj Avatar asked Nov 06 '22 15:11

kjmj


1 Answers

I did not work through the workshop you mention, but from reading the README of module 2 I understand that they are implementing User Authentication and Registration with Amazon Cognito User Pools.

Redirecting from a site which is inaccessible is fine, you must not ensure that it is never loaded. Let me explain why:

The "sensitive" information which is displayed on the site is not static. It is loaded from a REST backend in module 4. Since the authentication is static by means of JWT, the data is never loaded from the REST backend if the user is not authenticated.

So what should the page /rides.html do?

  • if the user is authenticated (i.e. has obtained a JWT which is valid) the REST backend should be called to obtain the data
  • if the user is not authenticated (i.e. no JWT present) or the JWT is present and not valid anymore the user should be redirected to the sign-in page; note that no sensible data was obtained from the REST backend before the redirect

EDIT:

In order to restrict access to one single object in S3, you could add a bucket policy like the following one to the s3 bucket:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::<your-bucket-name>/*"
        },
        {
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": "<your-user-arn>"
            },
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::<your-bucket-name>/rides.html"
        }
    ]
}

This will make all objects public except the rides.html file. If you want to access it, you will have to use a signed url. [1]
Please note that you must not use a bucket or object ACL which grants public access to everyone in conjunction with this approach since it might prevent the object from staying private.

Another approach (for using a federated user instead of a regular IAM user)

I do not know if the following works because of limitations in the docs [2], but you could give it a try.
It might be possible to use a web identity federation provider in the NotPrincipal attribute: "Federated": "cognito-identity.amazonaws.com". You could then narrow down which federated user has access to the rides.html object via condition keys (e.g. cognito-identity.amazonaws.com:sub). [3]

[1] https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-urls.html

[2] https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html

[3] https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html

like image 93
Martin Löper Avatar answered Nov 11 '22 17:11

Martin Löper