Amplify-cli: AccessDenied: Access Denied when trying to .put or .get on S3

Created on 7 Mar 2020  路  17Comments  路  Source: aws-amplify/amplify-cli

Describe the bug
When I try to get or put a file on S3 using Storage.put or Storage.get I get an access denied error.

Amplify CLI - 4.13.4
aws-amplify - 2.2.6

To Reproduce

I'm using React.

Steps to reproduce the behavior:

const awsKey = await Storage.put(fileName, pdfBlob, {level: 'public', type: 'application/json'})

I have a valid file name and blob. The interesting thing is this code worked before. I deleted my entire amplify instance and rebuilt it and that's when it stopped working. I was also getting a Client Not Authorized Error when I tried to use the IAM authRole for authentication on API Gateway to call a lambda function. I got around that by making a cognito authorizer and using that as the auth method.

I'm wondering if I'm missing something in the rebuilding that's causing the IAM roles to not work or be invoked..

I checked that the IAM roles and the policies that Amplify attaches to the cognito authRole and they are there.

Under "Last Activity" on the authRole in the IAM console it shows no prior activity. It seems like these roles are not being used to authenticate my user to put or get.

I noticed the same thing when I was struggling with the API Gateway IAM auth issue. I deleted the whole amplify project because I could only get the API Gateway to call a lambda function on my master branch and master environment. All other branch/environment combinations got not authorized error. When I rebuilt it, it stopped working on the master branch as well for the API Gateway, which leads me to believe there's some setting not right but I've checked all the obvious places for permissions and they are all the usual ones auto-generated by amplify that have worked before.

Debugging Window:
Screen Shot 2020-03-06 at 4 03 07 PM

pending-response pending-triage storage

Most helpful comment

@danmight @ashika01 I've been battling this issue all day, think I figured out the gist of it. When IdentityProvider has choose from token and your user has custom group assigned to them, the role from their group overrides the default identityPool auth role... Therefore when performing operations to S3, the system is looking at your group role, which has no S3 policies attached.

two other problems I had with storage category:

  • if you want unauthorised users to have s3 access, "Enable access to unauthenticated identities" must be ticked in your IdentityPool which is not set to false in my instance (unsure if amplify auth cat lets you update this from the cli but it is listed as an option in the parameters.json file)
  • running amplify storage update overwrites your cognito cloudformation template... everything seems fine EXCEPT if you have custom attributes... those get deleted and your stack deploy will fail as you cant delete cognito attributes.

All 17 comments

A follow up note to this, is that if I run the Policy Simulator it will return "allowed" when run on the buckets I'm trying to access, so the policy appears to be okay as well. I'm not sure why the calls are being denied when called through my app.

If I add the following bucket policy:

{ "Version": "2012-10-17", "Id": "Policy1583548206178", "Statement": [ { "Sid": "Stmt1583548203557", "Effect": "Allow", "Principal": "*," "Action": [ "s3:DeleteObject", "s3:GetObject", "s3:PutObject" ], "Resource": "arn:aws:s3:::XXXXXXXXXXXXXXXXX-staging/*" } ] }

It makes the bucket public (which I don't want) and I can execute a put.

If I change the principal to the following it fails. These are my attempts at workarounds since amplify does not specify any bucket policy when it makes the bucket.
{ "Version": "2012-10-17", "Id": "Policy1583548206178", "Statement": [ { "Sid": "Stmt1583548203557", "Effect": "Allow", "Principal": { "Federated": "cognito-identity.amazonaws.com" }, "Action": [ "s3:DeleteObject", "s3:GetObject", "s3:PutObject" ], "Resource": "arn:aws:s3:::XXXXXXXXXXXXXXXXXXX-staging/*" } ] }

I was able to solve this. When ampify generated the federated identity pool it set the "Get Role" to "From Token". I'm not sure if that is correct or not, but if I switch it to "Default Role" and make sure the authRole is set correctly for authenticated users, it works. However, this still doesn't fix the API gateway auth issue from my other issue above. I still have to use custom cognito authorizers for that. For whatever reason IAM roles don't work for authentication there.

Screen Shot 2020-03-08 at 8 34 40 AM

@danmight could you provide some info on how to setup amplify project? If you problem are with the policies / roles setup I think it could all be from cli setup phase and would recommend you track this with the CLI issue.

You can go ahead and close this. I don't have the console logs from when I set it up, but I don't think I chose anything crazy or did anything that didn't involved amplify add and follow the questions it asks. I was able to at least figure out a solution to move forward, so that is good!

@danmight Yeah, I have seen that certain times where something in the setup has been incorrect or something from cache messing around. As long as you got it going forward, its all good. If you have any other issues or need clarifications feel free to open up a new issue :)

@danmight @ashika01 I've been battling this issue all day, think I figured out the gist of it. When IdentityProvider has choose from token and your user has custom group assigned to them, the role from their group overrides the default identityPool auth role... Therefore when performing operations to S3, the system is looking at your group role, which has no S3 policies attached.

two other problems I had with storage category:

  • if you want unauthorised users to have s3 access, "Enable access to unauthenticated identities" must be ticked in your IdentityPool which is not set to false in my instance (unsure if amplify auth cat lets you update this from the cli but it is listed as an option in the parameters.json file)
  • running amplify storage update overwrites your cognito cloudformation template... everything seems fine EXCEPT if you have custom attributes... those get deleted and your stack deploy will fail as you cant delete cognito attributes.

@danielblignaut Genius! Thanks for posting what your follow up. This just connected the dot on the last piece for me. I could not figure out why an early version I had worked fine. I introduced groups on sign up later, so my original users did not have any assigned and that explains why they were working. I hadn't actually written code to do anything with the groups yet, but they were getting assigned and probably getting assigned with no permissions. Well done.

@danmight no problem... To fix the issue, I ended up having to do this nastiness inside the s3 cloudformation template... here's just a snippet from one of the policy's but you would need to update all of the "authenticated" policies (Would love to hear if this is advisable route or if there's a better potential solution as I'd have to remember to update this file every time I edit groups in my amplify setup):

"S3AuthPublicPolicy": {
            "DependsOn": [
                "S3Bucket"
            ],
            "Condition": "CreateAuthPublic",
            "Type": "AWS::IAM::Policy",
            "Properties": {
                "PolicyName": {
                    "Ref": "s3PublicPolicy"
                },
                "Roles": {
                    "Fn::Split": [
                        ",",
                        {

                            "Fn::Join": [
                                ",", [
                                    {
                                        "Ref": "authRoleName"
                                    },
                                    {
                                        "Fn::Sub": [
                                            "${deployName}-adminGroupRole,${deployName}-dietitianGroupRole,${deployName}-dietitianManagerGroupRole,${deployName}-userGroupRole",
                                            {
                                                "deployName": {
                                                    "Ref": "authcognitoUsersUserPoolId"
                                                }
                                            }
                                        ]
                                    }
                                ]
                            ]
                        }
                    ]
                },
                "PolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Action": {
                                "Fn::Split" : [ "," , {
                                    "Ref": "s3PermissionsAuthenticatedPublic"
                                } ] 
                            },
                            "Resource": [
                                {
                                    "Fn::Join": [
                                        "",
                                        [
                                            "arn:aws:s3:::",
                                            {
                                                "Ref": "S3Bucket"
                                            },
                                            "/public/*"
                                        ]
                                    ]
                                }
                            ]
                        }
                    ]
                }
            }
        }

You can see the horrible stuff happening in my roles array. The issue here is that you need to pass the role name (not ARN) into the roles array for assignment to your custom groups. However, you can't edit the outputs of the cognito user group's cloudformation as this file get's regenerated on every amplify push, overwriting your changes and the only outputs in that file are the role ARN not role name. Whilst you could hard code them into the s3 cloudformation, it would prevent your s3 storage working in the multiple environment setup in amplify, as each role name is prefixed with the environment's cognito user pool ID...

I'd suggest storage cat is reviewed for some of these mines and the role name is added to user group cloudformation template output or relook at that file being generated on every amplify push.

@danmight @danielblignaut So the policy is not configured properly when you do configuration from amplify add storage?

@ashika01 It configures it correctly unless you have groups assigned incognito. For some reason, it is not assigning the authRole that cognito builds and configures correctly if you assign a user to a group in cognito.

@ashika01

User role issue

as @danmight mentioned... to reproduce, run the following:

  1. add auth via amplify.
  2. add a user group to cognito
  3. add storage category
  4. create a user and add to that group
  5. login as user and attempt file upload

note that when logged in, the IAM role associated to the user is not {appname}-authRole, it is instead {cognito pool}-{user group name}GroupRole. This leads to an issue because the correct s3 permissions that are generated inside of the storage category's cloudformation template are associated only to {appname}-authRole or {appname}-unauthRole . I fixed this by using the snippet above however this could be refactored better. The reason why It's quite hacky is because the userPoolGroups cloudformation template can't be modified by the developer as it is generated on every amplify push and therefore changes are overwritten. My suggested change to this file was to add the role name's as outputs so that we can reference them directly to attach IAM policies to them. Unfortunately cloudformation only allows you to attach policy's by role name, not role ARN which is currently the only exported item.

Guest S3 access issue

if you want unauthorised users to have s3 access, "Enable access to unauthenticated identities" must be ticked in your IdentityPool which is not set to false in my instance (unsure if amplify auth cat lets you update this from the cli but it is listed as an option in the parameters.json file)...

see checkbox below.

Screenshot 2020-03-16 at 10 10 59

as far as I can tell, the issue here is that without this box being checked, your guest user won't receive a jwt token for guest requests (amplify does this automatically when configuring cognito as far as i can tell)... therefore when attempting to file upload, you don't have an access token and your user will get an access denied issue. I believe that "Enable access to unauthenticated identities" is an auth category config as it's in the parameters.json file. Perhaps when adding storage, there needs to be a note to the user that this has to be activated and if the user prompts yes, this setting is automatically changed.

Amplify push - Existing schema attributes cannot be modified or deleted

to reproduce,

  1. add auth category to your project
  2. add a custom schema attribute to your cognito cloudformation template
  3. run amplify push
  4. add storage category
  5. run amplify push

in this instance, do a diff between the auth category cloudformation files from after step 2 v after step 4. you will notice that adding storage regenerates your auth cloudformation and has removed the custom schema attributes that you added.

@danielblignaut Looks like this one happen in the CLI Configuration phase. I will transfer it to the CLI team. They should be able to help you :)

Hi @danielblignaut and @danmight

Regarding the *UserRole issue*

I followed the exact steps mentioned above, I am able to use put and get APIs with out any error. Can you send the amplify folder which has this error so that I can reproduce this to [email protected].

One more thing you can try is updating amplify-cli version and amplify-js version to latest and try again.

Let me know if this thing works for you.

@danielblignaut @danmight I think the issue is tied to the access policies for the users in a group? You are assuming that the group will inherit all the policies tied to an auth IAM role dy default? That's not the case actually. You'll have to go through the amplify update storage flow and select the operations you want a certain group to have access to and that's when the IAM role associated with the user pool group will be updated. Let me know if I'm understanding this incorrectly.

Let me know if above issue is solved. For now I am closing this issue , if you are still stuck , you can comment on this and I will reopen this issue.

@kaustavghosh06 @akshbhu exactly the reason. It's not necessarily a bug but I feel the workflow could be more intuitive. I'm not sure if there have been changes to the CLI since my last comment but perhaps updating the prompt when you add the storage category and there are user groups, we should notify the user of this? Or perhaps a note in the docs even. I don't mean to open this issue up again unnecessarily. I will run through my amplify settings today and try recreate with screenshots for you if it's still an issue.

hey guys I have the same issue , but on my end it works on the simulator but not on a device , I also believe its working as IAM is set up via CLI but fails then run on a device, is there any way I can specify Storage to use Cognito instead of IAM for auth?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

adriatikgashi picture adriatikgashi  路  3Comments

davo301 picture davo301  路  3Comments

ffxsam picture ffxsam  路  3Comments

mwarger picture mwarger  路  3Comments

nason picture nason  路  3Comments