Originally published at shieldly.io/blog.
NotAction is one of the most misunderstood IAM elements. Its name suggests denial but it does not deny anything. When paired with Effect: Allow, it grants access to every action in all of AWS except the ones you listed.
What NotAction Actually Means
NotAction inverts the Action element. Instead of listing what a statement covers, you list what it excludes — and the statement covers everything else.
{
"Effect": "Allow",
"NotAction": ["iam:*", "sts:*"],
"Resource": "*"
}
This allows every action across every AWS service except IAM and STS. That includes s3:DeleteObject, ec2:RunInstances, rds:CreateDBSnapshot, lambda:InvokeFunction, and everything else. The author almost certainly meant to restrict IAM access — they accidentally granted everything else.
The One Legitimate Use Case
NotAction with Effect: Deny is the one safe pattern. It is commonly used in Service Control Policies to create a "deny all except break-glass" control:
{
"Effect": "Deny",
"NotAction": [
"iam:CreateLoginProfile",
"sts:AssumeRole"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::123456789012:role/BreakGlassRole"
}
}
}
This denies everything except the listed break-glass actions, for everyone except the break-glass role.
How to Rewrite the Dangerous Pattern
If you wrote NotAction + Effect: Allow trying to deny specific actions, replace it:
Instead of this (grants everything except IAM):
{
"Effect": "Allow",
"NotAction": "iam:*",
"Resource": "*"
}
Write this (allows only what you need):
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::my-bucket/*"
}
Then add an explicit Deny for anything you want blocked:
{
"Effect": "Deny",
"Action": "iam:*",
"Resource": "*"
}
Effect: Deny with an explicit action list is not the same as NotAction Allow — the former creates a hard deny, the latter creates a broad allow. They are opposite things.
Catch IAM statement mistakes automatically — paste a policy into Shieldly's free AI-Powered analysis. No signup, no credit card.
Launch offer: code 90Off2M — 90% off first 2 months. Pro from $1.90/mo. shieldly.io/pricing












