S3 Block Public Access Silently Overrides an Explicit Bucket Policy Grant
Overview
S3 Block Public Access overrides a bucket policy grant only when that policy is public: RestrictPublicBuckets denies requests at request time, BlockPublicPolicy rejects the policy at save time, and account settings override bucket settings.
At a glance
- Symptom
- A caller that should have access under an explicit Amazon S3 bucket policy statement receives an Access Denied response, even though the policy document…
- Likely cause
- Amazon S3 Block Public Access settings, applied at the account level, the bucket level, or both, can silently negate a bucket policy statement that…
- Impact
- The immediate impact is wasted diagnostic effort: engineers repeatedly edit a bucket policy that was never the actual blocker, while the real control sits on a separate, easily…
- Verification signal
- Validation confirms that only the intended principals now succeed and every other principal still receives a denial.Re-run get-bucket-policy-status and confirm the reported public state matches the agreed intent.Test…
- Safe correction
- The correction is to reconcile the Block Public Access baseline with the intended access before touching the bucket policy again, rather than continuing to edit the policy statement.Confirm…
- Rollback or recovery
- Rollback restores the exact bucket policy and Block Public Access configuration captured during diagnosis, and is available at every stage of the correction.If validation fails, or if any…
Symptom
A caller that should have access under an explicit Amazon S3 bucket policy statement receives an Access Denied response, even though the policy document was accepted without a syntax or validation error when it was saved.
The pattern is easy to misdiagnose: the statement is present, the principal is named correctly, the action and resource ARNs match, and the console or CLI reported no error when the policy was applied. Engineers re-check the JSON, rewrite the statement, and still see the same denial, because the policy document is not the only control deciding the outcome.
False Assumption
The failure is caused by treating a successfully saved bucket policy as proof that the granted access is actually in effect.
Amazon S3’s policy editor and the put-bucket-policy API validate that a policy is well-formed JSON and grammatically valid IAM policy syntax. Neither check confirms that the resulting access will be permitted once every other control in the account is evaluated. Teams that treat a successful save as equivalent to working access skip the step that actually explains most denials against an apparently correct policy.
Root Cause
Amazon S3 Block Public Access settings, applied at the account level, the bucket level, or both, can silently negate a bucket policy statement once the policy counts as public, including statements in that policy that grant access to specific other accounts, without generating any error on the policy itself.
Block Public Access is evaluated independently of the policy document. A statement can be syntactically valid and logically consistent with the intended grant, while RestrictPublicBuckets suppresses the access at request time: if the bucket policy is public, S3 allows only AWS service principals and authorised users in the bucket owner’s account, blocking cross-account access even for statements that name a specific account. BlockPublicPolicy acts earlier, rejecting a public policy when it is saved, and the two ACL flags affect ACLs, not policies. Because these settings live outside the policy document, a reviewer reading only the bucket policy has no visual indication that the grant is being overridden elsewhere. S3 applies the most restrictive combination of the account-level and bucket-level settings, as documented in the AWS Block Public Access reference; confirm the effective settings for your account before treating this as the root cause.
Impact
The immediate impact is wasted diagnostic effort: engineers repeatedly edit a bucket policy that was never the actual blocker, while the real control sits on a separate, easily overlooked configuration surface.
Downstream effects include delayed data pipeline runs, blocked cross-account integrations, and failed automation that depends on timely S3 access. There is a second, more serious impact in the opposite direction: if an engineer resolves the denial by disabling Block Public Access broadly, rather than correcting the actual scope mismatch, every bucket that relied on that account-level control becomes exposed at the same time, not only the one bucket under investigation.
Diagnosis
Diagnosis is a read-only comparison between what the bucket policy grants and what Block Public Access currently permits, before any file is edited.
- Retrieve the bucket-level Block Public Access configuration with
get-public-access-block. - Retrieve the account-level Block Public Access configuration for the account that owns the bucket.
- Retrieve the current bucket policy status with
get-bucket-policy-statusto see whether S3 currently treats the bucket as public. - Save a timestamped copy of the current bucket policy document before making any change, so the exact prior state can be restored.
| Flag | Effect when true |
|---|---|
| BlockPublicAcls | New public ACLs are rejected; existing public ACLs are not automatically removed. |
| IgnorePublicAcls | Existing public ACLs are ignored when evaluating access. |
| BlockPublicPolicy | Saving a bucket policy that would grant public access is rejected; existing policies are not changed. |
| RestrictPublicBuckets | If the bucket policy is public, access is restricted to AWS service principals and authorised users in the bucket owner’s account, which also blocks cross-account grants in that policy. |
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowReadForPartnerAccount", "Effect": "Allow", "Principal": {"AWS": "arn:aws:iam::111122223333:root"}, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::example-bucket/shared/*" } ] }
This statement is syntactically correct and, on its own, is not public, so Block Public Access does not affect it. If the same policy also contains a public statement (for example "Principal": "*" without a restricting condition) and RestrictPublicBuckets is enabled at the bucket or account level, requests from the named partner account are denied too, and the policy document gives no indication why.
Correction
The correction is to reconcile the Block Public Access baseline with the intended access before touching the bucket policy again, rather than continuing to edit the policy statement.
- Confirm with the data owner what access the bucket is actually meant to allow, and to which principals.
- Compare that intent against the retrieved bucket-level and account-level Block Public Access settings.
- Where the denied access is a cross-account grant, remove or scope down the public statement so the policy is no longer public; Block Public Access then stops applying. Where a single bucket genuinely needs public access, adjust the bucket-level setting for that bucket only, noting that an account-level flag still wins; avoid changing the account-level setting for a single-bucket fix.
- Apply the reviewed, corrected bucket policy with
put-bucket-policy, using the previously saved backup file as the rollback reference.
Validation
Validation confirms that only the intended principals now succeed and every other principal still receives a denial.
- Re-run
get-bucket-policy-statusand confirm the reported public state matches the agreed intent. - Test the specific read or write operation as the intended principal in a non-production context and confirm a success response.
- Test the same operation as a principal that should remain excluded and confirm it still receives a denial.
- Review AWS IAM Access Analyzer for S3 findings for the bucket and confirm no unresolved public or cross-account finding remains outside the approved scope.
Rollback
Rollback restores the exact bucket policy and Block Public Access configuration captured during diagnosis, and is available at every stage of the correction.
If validation fails, or if any unintended principal gains access, restore the bucket policy from the saved backup file with put-bucket-policy, and restore the prior Block Public Access configuration values with put-public-access-block. Re-run the validation checks immediately after rollback to confirm the environment matches its state before the change began. Treat an account-level Block Public Access change as requiring a second approver and a documented rollback owner, given the number of buckets a single account-level setting affects.
Prevention
Prevent recurrence by making Block Public Access state visible alongside every bucket policy review, rather than reviewing the policy document in isolation.
- Record the intended Block Public Access baseline for each bucket alongside its policy, so future reviewers see both controls together.
- Route bucket policy changes and Block Public Access changes through the same change process, with account-level settings requiring an explicit, separate approval.
- Add a scheduled or event-driven check of IAM Access Analyzer for S3 findings so an unintended public or cross-account grant is flagged before it is reported as a denial or, worse, an exposure.
- Treat any request to disable Block Public Access outright as a signal to re-open the diagnosis, not as an approved fix.
Related reading
- A Bucket-Level Public Access Block Only Masks a Permissive ACL Until It Is Loosened
- An IAM Permissions Boundary Fails to Block Decrypt Access Granted by a KMS Key Policy
- Fixing AWS S3 AccessDenied When an EC2 Instance Role Reads a Bucket
- AWS Cross-Account AssumeRole Is Denied by a Mismatched Trust Policy
Apply the safer control
Before you change production
Confirm the affected scope, export the current configuration, and test the replacement control in a non-production environment first.
Fix commands and configuration
put-bucket-policyRestrictPublicBucketsBlockPublicPolicyVerify, roll back or escalate
Verify
Validation confirms that only the intended principals now succeed and every other principal still receives a denial.Re-run get-bucket-policy-status and confirm the reported public state matches the agreed intent.Test the specific read or write operation as the intended principal in a…
Rollback
Rollback restores the exact bucket policy and Block Public Access configuration captured during diagnosis, and is available at every stage of the correction.If validation fails, or if any unintended principal gains access, restore the bucket policy from the saved backup…
Escalate
Escalate when the blast radius is uncertain, the control cannot be tested safely, or remediation requires an outage or security exception.
Fixed? Get the next one before it hits you: The KBY Brief
Practical fixes for the systems you run, by email about twice a week. Unsubscribe at any time.
About this page
Dates
Published
Last updated
Corrections
No corrections are listed for this page. Some review sweeps corrected pages without naming each one; those are in the corrections log.
Was this useful?
Reports go to the site owner and are used to correct pages. Corrections are listed at /corrections.