Skip to main content
In this lesson we’ll cover how ACLs and resource policies control access to S3 buckets and objects, and how to change who can access a bucket. By default, a newly created S3 bucket is locked down. Only the bucket creator and the account root user can access it. Other IAM users in the same AWS account, anonymous/public users, and users in other AWS accounts cannot access the bucket unless access is explicitly granted.
Infographic titled "S3 Access" showing an S3 bucket with a lock and two AWS account boxes: in Account 1 the bucket creator and root user have access (green check) while other AWS users and anonymous/public users are denied (red X). In Account 2, users from another AWS account are also shown as denied.

What are resource (bucket) policies?

Resource policies are JSON documents attached to a resource that determine who can access that resource. For S3, a resource policy attached to a bucket is called a bucket policy. A bucket policy declares:
  • Principal — who can access the bucket (an IAM user/role/account or "*" for everyone),
  • Action — what operations are allowed or denied (for example, s3:GetObject),
  • Resource — which bucket or objects the statement applies to (ARNs),
  • Effect — Allow or Deny (and optional Conditions).
A presentation slide titled "S3 Bucket Policies." It contrasts "Resource Policy" (who has access to an S3 resource) with "S3 Bucket Policy" (who can access the bucket and what operations they can perform).
A minimal bucket policy looks like this:
Key fields in a bucket policy:
  • Version — policy language version (use "2012-10-17").
  • Statement — array of policy statements.
  • Sid — optional statement identifier.
  • Principal — who the statement applies to (IAM users, roles, accounts, or "*" for everyone).
  • Effect — "Allow" or "Deny".
  • Action — S3 actions (e.g., "s3:GetObject", "s3:PutObject", "s3:*").
  • Resource — bucket/object ARNs. Use arn:aws:s3:::bucket-name/* for object-level actions.
You can include multiple statements. Example: allow everyone to GetObject but explicitly deny a specific user:
Important: "Principal": "*" matches everyone — all authenticated AWS users and unauthenticated (public) users — so use it with caution.

Scoping access to prefixes and conditions

Bucket policies can restrict access to specific prefixes (folders) inside a bucket. For example, to allow an IAM user Daisy to retrieve only objects under the media/ prefix:
You can also use Conditions to further narrow applicability. Two common condition examples:
  • Restrict by source IP address:
  • Restrict API requests to specific prefixes (useful for scoping list operations). s3:prefix and s3:delimiter are commonly used to limit listing behavior; confirm action/condition applicability in the Amazon S3 actions, resources, and condition keys documentation.
Be mindful: combining "Principal": "*" with "Action": "s3:*" without additional restrictions grants very broad access.

Block Public Access — a safety net

To reduce accidental public exposure, AWS provides the Block Public Access settings. Even if a bucket policy would make a bucket public, AWS will prevent public access when Block Public Access is enabled at the bucket or account level. This setting acts as an extra safeguard; you must explicitly disable it before a public bucket policy (or ACL) can take effect.
Block Public Access is an additional, account- or bucket-level safeguard. Disabling it does not by itself make the bucket public — a bucket policy (or ACL) still must grant public access. The setting simply allows such policies to take effect when disabled.
A screenshot showing AWS S3 “Block public access” settings on the left and, on the right, a diagram of an S3 bucket with a lock icon preventing an anonymous/public user from accessing it.

IAM policies vs resource (bucket) policies vs ACLs

  • IAM policies are attached to identities (users, groups, roles) and grant or deny permissions to authenticated AWS principals.
  • Resource policies (bucket policies) are attached to S3 buckets and can grant access to specific principals, including anonymous/public users.
  • ACLs (Access Control Lists) are a legacy mechanism offering coarse-grained permissions such as READ, WRITE, READ_ACP, WRITE_ACP, and FULL_CONTROL. They are less flexible and generally discouraged.
Evaluation rules (what actually determines access):
  • An explicit Deny in any applicable policy wins and blocks access.
  • For access to succeed, there must be no explicit deny and at least one applicable policy (IAM or resource) must allow the action.
  • If the IAM policy allows but the bucket policy explicitly denies, access is denied.
  • If the bucket policy allows but the IAM policy denies (or lacks the permission), access is denied.
Table — quick comparison

Best practices

  • Prefer IAM policies and bucket policies over ACLs for new designs.
  • Use least privilege: grant only the actions and resources required.
  • Avoid "Principal": "*" unless you intend to allow public access and have verified Block Public Access settings.
  • Use Conditions (IP address, s3:prefix, aws:Referer, etc.) to reduce exposure.
  • Enable AWS S3 Block Public Access at the account and bucket levels to prevent accidental public access.
To summarize:
  • Bucket policies determine who (including public users) can access a bucket and what actions they can perform.
  • A policy statement consists of Principal, Resource, Effect, and Action (with optional Conditions).
  • IAM and bucket policies are evaluated together — both must allow the action (and none may deny it).
  • Only resource policies (or ACLs) can grant anonymous public access.
  • ACLs are legacy and limited — prefer policies.
A presentation slide titled "Summary" listing three numbered points about IAM: actions determine allowed operations, effects allow or deny actions, and bucket policies work alongside IAM policies. The slide features a turquoise gradient panel on the left.

Watch Video