Dev.to Security 🔐 Cybersecurity 👁 1 📖 1 min read

AWS IAM NotAction vs Deny: The Misread Statement That Grants Everything

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 actio

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

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.