Sometimes writing AWS IAM policies gets confusing. Especially if our policy authoring is reactive in nature instead of following a proactive permissions strategy.

The fact that IAM policies contain some restrictions doesn’t really help either.

To start off, let’s take a look at what the IAM policy evaluation order looks like:

Image for post
Image for post
Image courtesy Amazon Web Services IAM User Guide

Wow — this is complicated! Additionally some of the documentation and courseware suggest doing both allow and deny-statements.

What how?

Well the Amazon S3: Limits managing to a specific S3 Bucket example in the IAM User Guide shows the idea.

So here we’re allowing all S3 access on to a particular bucket and its contents, and then denying all other actions (for all other services!) and for all other resources.

So how do the NotAction and NotResource -elements work? If we take a look at the policy evaluation order we can see that the second step is “Evaluate all applicable policies”. Thus if a request comes in from a principal that has the above policy attached for reading an item from a DynamoDB table the above policy will be evaluated into a deny.

  • The first part of the policy allows S3-actions, so that would be skipped as not matching the request.
  • For the second part any DynamoDB-action will match the “NotAction”: “s3:*”-part thus a deny decision is made.
  • As a deny overrides any possible allows we will deny the request.

But wait a minute, wasn’t the policy evaluation logic deny by default anyway? Yes it is, and this kind of policy is only needed if you are feeling that you might (accidentally) give someone permissions they shouldn’t have.

There are more sane ways to use NotAction with Allow to, for example, allow full control except deletion.

This is way easier than having to explicitly list all S3-actions. But doesn’t that allow all other services? Would a DynamoDB table read be allowed with this kind of policy? Well no, as the resource in that request would be a DynamoDB-table instead of a S3-bucket.

Similarly we can restrict access to a particular resource by using the Deny-NotResource -pattern.

So here we are denying all S3-actions to all resources except one bucket and its contents. Note that this alone will not give access to that particular resource as an explicit allow is required somewhere else.

Combining Allow and NotResource becomes terribly frightening. Think of an innocent-looking policy like this:

So we’re probably trying to give full access to S3 except for a particular bucket and its contents here. However, we have just given all possible permissions (except access to that bucket) using this policy. And this doesn’t restrict anything as we also gave the permission to change policies themselves :D

The motivation for this blogpost came from a discussion on what NotAction: * or NotResource: * would do. There is a common misconception that they would invert the Effect which naturally isn’t true.

Remember the way that the evaluation logic works. It would first evaluate all applicable policies, thus any request with any action wouldn’t match the NotAction: *-pattern and any request with any resource wouldn’t match the NotResource: *-pattern. Thus they are practically no-ops.

I tested it (for completeness). Created a user with the inline policy:

And then tried to list buckets

As anticipated. If we add an Allow-permission that allow works normally as if the deny wouldn’t exist.

Written by

Cloud and AI/ML training and consulting. AWS Champion Authorized Instructor.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store