---
cuppy_hub: aws
cuppy_path: reference/s3/access-control.md
cuppy_section: docs
cuppy_doc: J2GR-47WC
cuppy_doc_uuid: a313a898-c9f0-45f0-8658-aa54def99156
cuppy_permalink: https://cuppy.io/aws/d/J2GR-47WC
cuppy_version: 4
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/aws/docs/reference/s3/access-control
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 0d07b18eb33b654cf9f82778ff158c4094506a5b3e3a50eac4bf26a64152e929
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# How S3 decides access

**S3 runs normal IAM policy evaluation (`reference/iam/policy-evaluation.md`), and adds three S3-only controls that can refuse a request IAM would allow:** Object Ownership (who owns an object, and whether ACLs exist at all), Block Public Access (which overrides "public" grants), and access point configuration. New buckets are private: ACLs disabled, all four Block Public Access settings on, SSE-S3 encryption.

## Default behaviour

- **No bucket policy:** identities in the bucket owner's account can use the bucket if their own IAM policies allow it; other accounts and anonymous requests are denied.
- **Same account:** an Allow in either the IAM policy or the bucket policy is enough.
- **Cross-account:** both the caller's IAM policy and the bucket policy must allow.
- **Bucket vs object ARNs:** bucket actions (`s3:ListBucket`) use `arn:aws:s3:::<bucket>`; object actions (`s3:GetObject`, `s3:PutObject`) use `arn:aws:s3:::<bucket>/*`. A statement with only one form silently misses the other.
- **`s3:ListBucket` also changes errors:** without it, a request for a missing object returns 403 instead of 404.

## Object Ownership and ACLs

| Setting | Owner of new objects | ACLs |
|---|---|---|
| **Bucket owner enforced** (default for new buckets; recommended) | Always the bucket owner | Disabled; they no longer affect access. A PUT carrying any ACL other than `bucket-owner-full-control` fails with `AccessControlListNotSupported` (400). |
| **Bucket owner preferred** | Bucket owner if the upload carries `bucket-owner-full-control`, otherwise the writer | Enabled |
| **Object writer** | The uploading account | Enabled |

Why it matters: **a bucket-policy Allow applies only to objects the bucket owner owns; a bucket-policy Deny applies to all objects.** In a bucket with ACLs enabled, an object uploaded by another account can be granted only by its ACL, so the bucket owner may get 403 on its own bucket.

Moving to Bucket owner enforced: first migrate any ACL grants to bucket-policy statements, find requests that depend on ACLs, and update policies that use ACL condition keys. Afterwards the bucket owner owns everything; reads of ACLs still work and show only the owner. Permissions: `s3:PutBucketOwnershipControls` and `s3:GetBucketOwnershipControls`.

```
aws s3api get-bucket-ownership-controls --bucket <bucket>
```

## Block Public Access

Four independent settings, at the access point, bucket and account levels; at the **organization** level all four are applied together as one policy and override account settings. S3 enforces the **most restrictive** combination of the levels that apply. Account settings apply in every Region (propagation can take time). There is no per-object setting.

| Setting | Effect | Denial reads |
|---|---|---|
| `BlockPublicAcls` | Rejects `PutBucketAcl`/`PutObjectAcl` with a public ACL, `PutObject`/`CopyObject`/POST with a public ACL, and (account level) `CreateBucket` with a public ACL. Existing ACLs untouched. | `because public ACLs are prevented by the BlockPublicAcls setting in S3 Block Public Access.` |
| `IgnorePublicAcls` | Ignores public ACLs on the bucket and its objects. | implicit: `because no resource-based policy allows …` |
| `BlockPublicPolicy` | Rejects `PutBucketPolicy` (and access point policies) that would be public. Existing policies untouched. Apply it at the **account** level: at bucket level, someone who can edit the bucket policy could turn it off. | `because public policies are prevented by the BlockPublicPolicy setting in S3 Block Public Access.` |
| `RestrictPublicBuckets` | For a bucket or access point whose policy is public, allows only AWS service principals and the owner's account; blocks all cross-account and anonymous access, **including non-public statements in the same policy**. | explicit: `with an explicit deny in a resource-based policy` |

Turning a setting off does not change policies or ACLs, so anything public under it becomes public again immediately. `GetBucketAcl`/`GetObjectAcl` report the effective permissions, not the stored ACL.

### What S3 counts as "public"

- **ACL:** grants anything to the `AllUsers` or `AuthenticatedUsers` groups.
- **Bucket policy:** S3 starts by assuming public, and a statement is non-public only if it limits access with **fixed values** (no wildcards, no policy variables) of at least one of: a specific principal (or `aws:PrincipalOrgID`), `aws:SourceIp` with a narrow range, `aws:SourceArn`, `aws:SourceVpc`, `aws:SourceVpce`, `aws:SourceOwner`, `aws:SourceAccount`, `aws:userid` (outside the `AROLEID:*` pattern), `s3:DataAccessPointArn`, `s3:DataAccessPointAccount`.
- `aws:SourceIp` ranges broader than `/8` (IPv4) or `/32` (IPv6), excluding RFC 1918 private ranges, count as public.
- `"aws:SourceVpc": "vpc-*"` is public; `"aws:SourceVpc": "vpc-<id>"` is not.
- One public statement makes the whole policy public, which brings `RestrictPublicBuckets` into force for every statement in it.
- A policy that allows an action S3 does not support can be judged public by Block Public Access even when IAM Access Analyzer disagrees; remove unsupported actions.

Permissions: `s3:GetBucketPolicyStatus`, `s3:Get/PutBucketPublicAccessBlock`, `s3:Get/PutAccountPublicAccessBlock` (DELETE uses the PUT permission).

## Access points

Requests through an access point are also checked against its network origin (a **VPC** origin rejects anything not from that VPC), its own Block Public Access settings (fixed at creation), the access point policy, and, for cross-account access points, the bucket policy, which must authorize requests from the access point. An access point with a VPC origin is always non-public. Unlike bucket policies, an access point policy granting to `s3:DataAccessPointArn` wildcards is public.

## If a policy locks everyone out

A bucket policy that denies everyone can be removed by the account root user. In an AWS Organizations member account, a privileged root session started from the management account can delete it.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 131 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/aws/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
