S3 Bucket Policy vs IAM Policy: Which One Do You Need?

5 min·Jul 18, 2026
AI Summary

An IAM policy is identity-based (attached to a user/role, no Principal) and answers "what can this identity do?". A bucket policy is resource-based (attached to a bucket, always has a Principal) and answers "who can touch this bucket?". Access is the union of allows across both, but any explicit Deny in either wins. Use IAM for your own principals, bucket policies for cross-account or anonymous access.

AWS S3 Bucket Policy — Secure Public Read
An S3 bucket policy that allows public read of static assets while forcing HTTPS and blocking every other action — a common CDN/origin setup.
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-public-assets/*"
    },
    {
      "Sid": "DenyInsecureTransport",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::my-public-assets",
        "arn:aws:s3:::my-public-assets/*"
      ],
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      }
    }
  ]
}

Both an S3 bucket policy and an IAM policy can grant s3:GetObject. They are not interchangeable — they attach to different things and evaluate together.

The one-line difference

  • IAM policyidentity-based. Attached to a user, group or role. Has no Principal (the identity it attaches to is the principal). Answers: "what is this identity allowed to do?"
  • Bucket policyresource-based. Attached to the bucket. Always has a Principal. Answers: "who is allowed to touch this bucket?"

Side by side

IAM policyBucket policy
Attaches toUser / group / roleThe bucket
Has Principal?NoYes (required)
Good forYour own principalsCross-account, anonymous/public
Lives inIAMS3

How they combine

For a request to succeed, AWS evaluates both:

  1. Collect every applicable statement from IAM policies and the bucket policy.
  2. If any statement has an explicit Denydenied. Deny always wins.
  3. Otherwise, if any statement has an Allowallowed.
  4. Otherwise → denied by default.

So for same-account access you only need an Allow in one of them. For cross-account access you generally need an Allow on both sides — the bucket policy trusts the other account, and that account's IAM lets its principal use S3.

Which do I reach for?

  • Granting your own role read access → IAM policy.
  • A different account needs access → bucket policy (name their account/role as Principal) + their IAM.
  • Anonymous public read → bucket policy with Principal: "*".
  • Blanket guardrail (deny non-HTTPS, deny outside a VPC) → bucket policy Deny — it covers every principal at once.

Verify the combination, not just one file

Because a Deny in either policy wins, reading one file in isolation lies to you. Paste both into the workspace and ask "does this identity get GetObject on this bucket, and why?" — the AI walks the allow/deny evaluation across both documents.

FAQ

What is the core difference?

An IAM policy is identity-based: it attaches to a user, group or role and has no Principal. A bucket policy is resource-based: it attaches to the bucket and always names a Principal.

If both apply, which wins?

Access is the union of Allows across both, but an explicit Deny in either one always wins. For same-account access you only need an Allow in one of them.

When must I use a bucket policy?

For cross-account access and for anonymous/public access — those cases need a Principal, which only a resource-based policy has.