Short answer: identity side vs resource side
An IAM identity-based policy is attached to an IAM user, group or role. It defines which actions that identity may perform on which resources. The policy does not include a Principal element because the attached identity is already the principal.
An S3 bucket policy is attached to an S3 bucket. It is a resource-based policy and normally identifies the allowed or denied principal. It can grant another AWS account or service access, and it can enforce bucket-wide conditions such as transport security or an organization boundary.
Decision rule
Start with three questions: Who is calling? Who owns the bucket? Does the bucket need a rule that applies regardless of the caller's own permissions? The answers reveal whether the permission belongs on the identity, the bucket or both.
Compare the policies before writing JSON
Four architecture scenarios and the better choice
1. Same-account EC2 role reads one private prefix
Attach a least-privilege identity policy to the EC2 role allowing s3:GetObject on arn:aws:s3:::catalog-images/products/*. The role supplies temporary credentials and the policy grants only the required action and prefix. A bucket policy is not automatically required when the role and bucket share an account and no other control denies access.
2. A workload in Account A writes to a bucket in Account B
Authorize the action from both account boundaries. The caller's role needs permission to call the S3 operation, and the destination bucket policy must trust the role or account as a principal. Scope the resource to the required bucket or object prefix and add conditions where they reduce risk.
3. CloudFront uses a private S3 origin
A bucket policy can grant the CloudFront service principal access for a specific distribution through Origin Access Control conditions. This is a resource-side service grant; do not make the bucket public merely so CloudFront can retrieve objects.
4. Every caller must use TLS
Use a bucket-policy deny condition for requests where aws:SecureTransport is false. Because explicit deny wins, the guardrail applies even when an identity policy elsewhere allows the S3 action.
How AWS evaluates the request
- Authenticate the principal: identify the role session, user, service or anonymous caller.
- Collect applicable policies: evaluate identity policies, the bucket policy and relevant control policies.
- Look for an explicit deny: a matching explicit deny overrides an allow.
- Check the account boundary: cross-account access must be authorized correctly by both the caller and resource-owning sides.
- Apply limiting controls: permissions boundaries, session policies, organization SCPs, VPC endpoint policies and S3 Block Public Access can narrow the result.
- Check related services: an encrypted object may also require permission on its KMS key.
The safest SAA-C03 answer grants only the necessary action, resource and principal, then uses conditions and centralized controls deliberately. Adding a broad second allow rarely fixes an unexplained deny.
Troubleshoot S3 AccessDenied systematically
The role policy says Allow, but GetObject fails
AccessDenied: s3:GetObject
Bucket: reports-prod
Key: monthly/report.csvThe identity allow proves only one part of the authorization path. It does not prove that the ARN, bucket policy, KMS key or organization controls permit the request.
Trace principal, action, resource and denies
- Confirm the actual role session with STS caller identity.
- Compare the object ARN—not only the bucket ARN.
- Inspect bucket-policy principal and conditions.
- Search for explicit denies and boundary controls.
- Check KMS authorization for encrypted objects.
Choose the policy type from the ownership and trust boundary. Then troubleshoot the complete evaluation path instead of repeatedly adding permissions.
Illustrative training scenario—not a customer incident or copied certification question.S3 bucket policy vs IAM policy FAQs
What is the difference between an S3 bucket policy and an IAM policy?
An IAM identity-based policy attaches to a user, group or role and defines what that identity can do. An S3 bucket policy attaches to a bucket, is resource-based and can name the principals that may access that bucket and its objects.
Do I need both an IAM policy and a bucket policy for S3?
Not always. In one account, an identity-based allow can be sufficient when no other policy denies access. Cross-account designs commonly need permission from the caller's account and the bucket owner's resource policy. Explicit deny, permissions boundaries, session policies and organization controls can still restrict the result.
Which policy should grant an EC2 role access to a same-account bucket?
A least-privilege policy on the EC2 role is often the simplest permission grant. Use the bucket policy when the bucket needs a resource-side rule, such as allowing a service principal, limiting approved principals, requiring TLS or enforcing organization-level conditions.
Why does S3 still return AccessDenied when a policy allows GetObject?
Check the exact object ARN, role session, bucket policy, explicit denies, organization SCPs, permissions boundaries, session policies, KMS key permissions, VPC endpoint policies and S3 Block Public Access. The allow may apply to the wrong principal, action or resource, or another control may deny the request.
Can a bucket policy make an S3 bucket public?
A permissive resource policy can express public access, but S3 Block Public Access can reject or override public-policy behavior. Public access should be an intentional exception; prefer private origins and controlled identities for application architectures.
Official AWS sources
Verify implementation details in AWS documentation for identity-based and resource-based policies, policy evaluation logic, S3 bucket policies and S3 bucket-policy examples. Re-check current service documentation before applying a policy to production.