Improving policy readability with NotAction
NotAction
. In some cases, when you want to deny only a few actions and want to allow many of them, choosing this policy element can be a good option.
1. The problem
Alice and Bob work for the same company. Alice is a DevSecOps engineer, and Bob is in a non-technical department.
Alice is an administrator of the AWS accounts of the company. She is reliable and knows her stuff. Bob is new, and while he is probably reliable and knows his stuff in his field, he is not a technical person.
Alice just got the task to give Bob access to some department buckets in S3. He should be able to download and upload files to the buckets and modify them, too, and it is a requirement that Bob could not delete the objects, the buckets, and the object tags.
2. Possible solutions
Alice has a couple of options to mitigate the risk of data loss, which includes versioning and MFA delete, but she decided to disallow Bob the entire deletion operation.
She wants to solve this problem with IAM policies, and wants AWS to display big red error messages when Bob attempts to delete anything from the bucket or the bucket itself.
2.1. Allow what is needed
Alice can write a policy for Bob where she displays all actions that she wants to allow him except the forbidden ones.
It means the Bob can have all permissions except s3:DeleteBucket
, s3:DeleteObject
,s3:DeleteObjectTagging
and s3:DeleteBucketPolicy
(just to be on the safe side).
Part of the identity-based policy assigned to Bob can look like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectTagging",
"s3:ListBucket",
"s3:PutObject",
// ... and many more actions
],
"Resource": [
"arn:aws:s3:::MY-BUCKET-NAME",
"arn:aws:s3:::MY-BUCKET-NAME/*"
]
}
]
}
I counted 128 IAM permissions for S3 today (S3 Object Lambda and S3 Outposts excluded), which means that Alice needs to list a lot of actions if she wants to allow Bob full S3 experience except deleting objects, tags, and buckets.
This policy is hard to read and is very long. If Alice creates a couple more statements like this, she might exceed the policy size limit, too.
2.2. Use managed policies
Alice could use managed policies, which provide permissions for common use cases.
AWS provides the AmazonS3FullAccess
and AmazonS3ReadOnlyAccess
managed policies for S3.
AmazonS3FullAccess
looks like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*",
"s3-object-lambda:*"
],
"Resource": "*"
}
]
}
The *
includes the delete actions, so she decides not to go with this policy.
The AmazonS3ReadOnlyAccess
managed policy, on the other hand, does not allow Bob to upload objects to the bucket, for example, so it is too narrow for him.
2.3. Deny deletion
Alice can decide to add an explicit deny to the delete actions. She can write something like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": [
"s3:DeleteObject",
"s3:DeleteBucket",
"s3:DeleteObjectTagging",
"s3:DeleteBucketPolicy",
],
"Resource": [
"arn:aws:s3:::MY-BUCKET-NAME",
"arn:aws:s3:::MY-BUCKET-NAME/*"
]
}
]
}
It looks good because explicit deny always wins no matter what, so Bob will not be able to delete anything from the bucket.
The problem is that the necessary actions (read and write) are still not allowed. Alice only denied deletion but she did not allow anything. Bob cannot get any objects from the bucket, and he cannot upload anything there either. His permission will need to contain an explicit allow for all other actions, and we are again back to point 2.1.
3. Use NotAction
IAM has a policy element called NotAction
that acts like an inverse Action
.
The meaning of NotAction
is every action but. Given the scenario above, Alice can write a policy like this and attach it to Bob’s identity:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"NotAction": "s3:Delete*",
"Resource": [
"arn:aws:s3:::MY-BUCKET-NAME",
"arn:aws:s3:::MY-BUCKET-NAME/*"
]
}
]
}
The policy above means that Bob is ALLOW
ed to do everything except the Delete
actions on the bucket called MY-BUCKET-NAME
. Initially, Alice wanted to prevent Bob from deleting objects, buckets, tags, and bucket policy. She can achieve it with just one line of code by replacing the Action
element with NotAction
. (In fact, this policy disallows more than the required four actions because S3 has more Delete
APIs. If Alice wants to be less strict, she can list these four actions in an array as the value of the NotAction
key.)
This policy will result in an implicit deny for example, for the s3:DeleteObject
actions because Alice explicitly allows (Effect: Allow
) everything but s3:Delete*
. It means that Bob cannot delete any objects from the bucket because he does not have explicit permission to do so.
4. Summary
We can create shorter, more concise policies using NotAction
. In some cases, we can avoid listing many actions, which will make the policy statements more readable.
NotAction
works well when we want to make a few exceptions from a large group of actions, like in the example above.
5. References and further reading
IAM JSON policy elements reference - collection of all policy elements, including NotAction
Policy evaluation logic - describes how IAM decides when to allow or deny an action