s3 IAM woes when using serverless
Recently I was attempting to deploy a new lambda server over some existing aws architecture, the s3 buckets already existed as well as lots of permissioning. This should be easy? Arguably it was easy and probably would have been easier if I already knew AWS/IAM/etc - though I don’t so pain was in store for me.
In general my serverless configuration for the aws/iam permissions looked like this;
1 | provider: |
Which I thought would be ok, as this was the generic snippet of code in which I was attempting to list a buckets objects and get tagging information on them;
1 | const client = new S3Client({ |
This worked fine locally when running serverless --offline
as the S3Client
would grab my local AWS credentials which had (seemingly) the same permissions. This was a sort of, false reality for me, as it took me a moment to even realize that this was happening. After figuring it out, of course it was using my local credentials which had already been over permissioned. Though when serverless
bundled and pushed everything utilizing CloudFormation
, it was not provisioning the correct permissions for the lambda. This lead in the client.send
throwing an Access Denied
error. So helpful, just tell me what permission I need already.
Finding the permissions
Per some Googling and reading of the documentation, the command ListObjectsV2Command;
1 | To use this operation, you must have READ access to the bucket. |
So we will need READ
access, meaing we should be able to s3:ListBucket
. I assumed READ
meant s3:GetObject
, so I think we got it, it looks like we already had this?
For GetObjectTaggingCommand the documentation states;
1 | To use this operation, you must have permission to perform the s3:GetObjectTagging action. By default, the GET action returns information about current version of an object. For a versioned bucket, you can have multiple versions of an object in your bucket. To retrieve tags of any other version, use the versionId query parameter. You also need permission for the s3:GetObjectVersionTagging action. |
So s3:GetObjectTagging
is likely enough? Even though we haven’t gotten to this line yet in our execution.
Over-permissioning for Testing
Annoyingly I tried many permutations and couldn’t seem to get anything right, so I tried just over permissioning it to see if this would simply allow it;
1 | - Effect: Allow |
This above one worked - as excepted. At least at this point we know it is possible and we can try to trim down the permissions.
Minimizing permissions
Re-(re-re-re-)reading AWS docs, I tried to break out the permissions into different roles to avoid over permissioning things. Something I had missed originally was that you want to literally list a bucket (root directory) with no glob when specifying s3:ListBucket
which is required for ListObjectsV2Command
so this should work;
1 | iam: |
This allowed our ListObjectsV2Command
to work! Now we got an error on the GetObjectTaggingCommand
. Digging back into this side, I added the s3:GetObject
and s3:GetObjectTagging
permissions to the globbed bucket;
1 | iam: |
Excellent, this worked as well. Now to minimize the scope of what this lambda is allowed to access.
Final minimization of scope
Since I originally didn’t set up these buckets, there actually had been a decent amount of files stored here and while this lambda doesn’t try to interact with it, I just don’t want to let it even have permissions to look at those files. Per the example, I abstracted it to some/folder/struct/inside/bucket/
and let’s pretend I also want to access some/other/folder
;
1 | iam: |
Bingo! Once you see it all layed out and have done it once, it all makes more sense and seems simple. Though, when you’re grinding for a day or two on the issue and waiting for the lambda to compile/upload/etc it can be quiet annoying…