AWS
S3
ACL
public access
cloud storage

AWS S3 make public via ACL disabled?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If S3 says you cannot make an object public via ACL, the bucket is usually configured with modern ownership and public-access protections. In current S3 setups, this is expected behavior: ACLs may be disabled entirely, and public access is meant to be controlled with bucket policy plus Block Public Access settings instead.

Why ACLs Can Be Disabled

Two S3 features commonly cause this behavior:

  • Object Ownership set to BucketOwnerEnforced
  • Block Public Access settings that reject public ACLs or public policies

When BucketOwnerEnforced is enabled, ACLs are disabled for the bucket. That means commands such as --acl public-read fail because the bucket no longer accepts ACL-based ownership or permission changes.

The Modern Way To Make Content Public

If the goal is public read access for objects, the usual path is:

  1. keep or accept bucket-owner-enforced ownership
  2. adjust Block Public Access if public access is truly intended
  3. add an explicit bucket policy allowing s3:GetObject

A minimal public-read bucket policy looks like this:

json
1{
2  "Version": "2012-10-17",
3  "Statement": [
4    {
5      "Sid": "PublicReadObjects",
6      "Effect": "Allow",
7      "Principal": "*",
8      "Action": "s3:GetObject",
9      "Resource": "arn:aws:s3:::example-bucket/*"
10    }
11  ]
12}

Apply it with the AWS CLI:

bash
aws s3api put-bucket-policy \
  --bucket example-bucket \
  --policy file://public-read-policy.json

That is the supported public-access model for many modern S3 buckets.

Check The Current Bucket Settings

Before changing anything, inspect the controls that are currently blocking public access.

bash
aws s3api get-bucket-ownership-controls --bucket example-bucket
aws s3api get-public-access-block --bucket example-bucket

If the bucket uses BucketOwnerEnforced, then ACL-based public access is off by design.

If Block Public Access is enabled, even a correct public bucket policy may still be rejected or ignored depending on which block settings are turned on.

Example: Allow Public Policy Instead Of Public ACLs

Suppose the bucket should serve static assets publicly. You do not need object ACLs for that. You need a bucket policy and public-access-block settings that permit the policy.

bash
1aws s3api put-public-access-block \
2  --bucket example-bucket \
3  --public-access-block-configuration \
4  BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=false,RestrictPublicBuckets=false

This configuration still blocks ACL-based public exposure while allowing a deliberate public bucket policy.

That is often the safest compromise when the bucket really must be public.

If You Truly Need ACLs

Sometimes legacy software expects ACLs. In that case, you would need to stop using BucketOwnerEnforced ownership controls and switch to an ownership mode where ACLs are enabled.

That is usually not the best fix unless you have a hard compatibility requirement. AWS has been moving users away from ACL-centric designs because policy-based access is easier to reason about and audit.

Public Access Is A Security Decision

Do not treat public-read configuration as a mechanical checkbox. If the bucket stores anything except intentionally public assets, stop and verify the requirement before disabling protections.

A safer design for many applications is to keep the bucket private and serve objects through signed URLs, CloudFront, or an application layer that enforces access rules.

Common Pitfalls

The most common mistake is trying aws s3 cp --acl public-read against a bucket where ACLs are disabled. That command path cannot work because the bucket rejects ACL-based permission changes.

Another issue is changing the bucket policy while leaving Block Public Access in a mode that still prevents public access. Both layers must be aligned.

Teams also sometimes assume that making the bucket public is the only way to share files. In many cases, signed URLs or CloudFront are better and safer.

Finally, do not re-enable ACLs casually just to satisfy an old deployment script. If the bucket was created with modern ownership controls, policy-based access is usually the intended design.

Summary

  • Public ACLs may be disabled because the bucket uses BucketOwnerEnforced ownership controls.
  • Block Public Access can also prevent public exposure even when a policy exists.
  • The modern way to allow public reads is usually a bucket policy, not --acl public-read.
  • Check ownership controls and public-access-block settings before troubleshooting further.
  • Re-enable ACLs only if a legacy workflow truly requires them.

Course illustration
Course illustration

All Rights Reserved.