
Bucket policy vs IAM policy is a distinction that trips people up because both are written in the same JSON policy language and both can grant or deny the exact same S3 permissions. The real difference isn't what they can express, it's what they're attached to. AWS's own documentation draws the line precisely: one is "a resource-based policy that is attached to an AWS resource, such as a bucket policy for a bucket," the other is "an identity-based policy that is attached to an AWS Identity and Access Management (IAM) identity, such as an IAM user, group, or role." That single difference in attachment point is what determines which one can actually do a specific job the other structurally cannot.
TL;DR:
Both policy types use the exact same JSON structure, the same actions, the same conditions. What differs is where the policy lives. An IAM policy lives on the identity making the request, it travels with that user, group, or role wherever it goes across AWS services. A bucket policy lives on the S3 bucket itself, it applies to that bucket regardless of which identity, inside or outside your account, is making the request.
AWS describes an identity-based policy as one you attach "to IAM users, groups, or roles in your account," used to "grant an IAM identity access to your buckets or objects." The practical implication is centralization: manage a user's entire AWS footprint, S3 included, from one place. AWS's own guidance names a specific scenario where this wins clearly: "if you have a very large number of buckets with different access permissions for each bucket, and only a few user roles to manage, you can use an IAM policy for users, groups, or roles," rather than maintaining a separate bucket policy on every single bucket.
A bucket policy is, in AWS's own words, "a JSON-formatted IAM resource-based policy that is attached to a particular bucket," used to "grant other AWS accounts or IAM identities permissions for the bucket and the objects in it." Because it lives on the resource rather than an identity in your account, it can name principals your IAM system has no relationship with at all, another AWS account entirely, a specific AWS service, or, if written that way, the public.
This is the clearest, least ambiguous dividing line between the two, and AWS states it as a hard rule rather than a soft recommendation: "to grant permission to another AWS account, you must use a bucket policy or one of the following recommended access management tools. You cannot use an identity-based access policy for this use case." An IAM policy, no matter how it's written, only governs identities inside your own account. If the goal is letting a completely separate AWS account read from or write to your bucket, a bucket policy isn't the better option, it's structurally the only option among these two.
A common misconception treats these as alternatives you pick between. AWS's documentation describes the actual evaluation model directly: "when Amazon S3 receives a request, it must evaluate all of the access policies to determine whether to authorize or deny the request." Every applicable policy, IAM policies attached to the requesting identity and any bucket policy on the target bucket, gets evaluated together on every single request. That means the two aren't competing tools, they're layers that combine, which is also exactly why a permission that looks correct in one policy can still fail if a conflicting deny exists in the other.
For anything with genuinely complex permission requirements, this is a real practical ceiling, not a theoretical one. AWS states plainly that "both bucket policies and identity-based policies have a 20 KB size limit." A sufficiently complex set of conditions, principals, and resource ARNs can actually hit that ceiling, at which point AWS's own guidance is to look at other access management tools, like IAM groups or S3 Access Points, rather than trying to cram everything into a single oversized policy document.
AIOZ Storage doesn't implement either of these mechanisms. Its access-control model is built on macaroons, bearer tokens carrying their own cryptographic proof of authorization, scoped to exactly four actions per bucket, rather than a JSON policy document attached to either an identity or a resource. That's a genuinely different architecture, closer to capability-based access control than to either the identity-based or resource-based model this article covers, worth knowing plainly if you're coming to AIOZ Storage expecting to write an IAM-style or bucket-policy-style JSON document, since that's not the shape its permission system takes.
What's the difference between a bucket policy and an IAM policy?
Attachment point. An IAM policy attaches to a user, group, or role and travels with that identity across AWS services. A bucket policy attaches directly to a bucket and applies to any request against it, regardless of which identity is making the request.
Can an IAM policy grant access to another AWS account?
No. AWS states directly that identity-based policies cannot be used for cross-account access, only a bucket policy (or a similar resource-based tool) can grant permissions to a completely separate AWS account.
Does S3 use the bucket policy or the IAM policy, not both?
Both, together. S3 evaluates every applicable policy on each request, IAM policies attached to the requester and any bucket policy on the target bucket, rather than picking one and ignoring the other.
What's the size limit on these policies?
20 KB for both bucket policies and identity-based (IAM) policies, per AWS's own documentation. Genuinely complex permission requirements can actually hit that ceiling.
When should you use an IAM policy instead of a bucket policy?
When you're managing a large number of buckets with a small number of user roles, centralizing permissions in IAM is simpler than maintaining a separate bucket policy per bucket, and when you also need to manage that identity's access to non-S3 AWS services from one place.
When should you use a bucket policy instead of an IAM policy?
When you need to grant access to a different AWS account, a specific AWS service principal, or you want to control access based on something outside AWS IAM identity entirely, like a requester's IP address.
Does AIOZ Storage use bucket policies or IAM policies?
Neither. AIOZ Storage's access-control model is built on macaroons, bearer tokens with their own embedded authorization, a capability-based design rather than either the identity-based or resource-based JSON policy model this article covers.

AIOZ Storage has no official MCP server yet. Here is a working MCP server for AIOZ Storage, built with the official Python SDK and boto3, tools included.

What is an MCP server: a standard letting AI agents like Claude use tools and data through one protocol. How MinIO and Azure apply it to object storage.

S3 access logs vs CloudTrail: AWS recommends CloudTrail, but each one catches real events the other misses. Speed, cost, and coverage, compared directly.

Eventual vs strong consistency: whether a read right after a write sees the new data immediately. S3 ran on the first model for 14 years, then changed it.

Bucket policy vs IAM policy: one attaches to the resource, one attaches to the identity. What each can do that the other can't, and how S3 evaluates both.

SSE-S3 vs SSE-KMS vs SSE-C: who manages the encryption key, and what that decision actually costs you. Includes the real 2026 default change to SSE-C.