Cloud & Infrastructure Security
How to check if your AWS S3 buckets are public
A step-by-step way to see whether your S3 storage is open to the internet, turn on Block Public Access and fix the usual leaks.
You can check whether your Amazon S3 buckets are open to the internet using only the AWS console. Start with the account-level Block Public Access setting, then look at each bucket's policy and permissions, then use the free access analysis AWS provides.
This post is for the person who owns the AWS account. Run these checks only in an account you own or have written permission to review. Console wording changes over time, so follow the AWS documentation linked in each step if your screen looks different.
Why public buckets cause leaks
An S3 bucket holds files such as customer uploads, invoices, backups and exports. Per AWS, new buckets, access points and objects do not allow public access by default. A leak happens when someone changes that, often to fix a quick problem: a developer makes a file public to share it, or adds a broad policy to get an app working, and it stays that way.
AWS's Block Public Access page (opens in a new tab) says public access is granted to buckets and objects through access control lists (ACLs), access point policies, bucket policies, or all of them. That is why you check more than one place.
Check the account-level Block Public Access setting
Block Public Access is a switch that overrides policies and ACLs. AWS describes four settings, which can be used in any combination: BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy and RestrictPublicBuckets. AWS recommends turning on all four at account level, unless you have a use case that needs public access.
Steps in the console, based on the account-level instructions (opens in a new tab):
- Sign in and open the Amazon S3 console.
- In the left menu, choose Account and organization settings.
- Under Block Public Access settings for this account, read the four settings and whether each is on.
- To change them, choose Edit, pick the settings, choose Save changes, and type
confirmwhen asked.
Two details worth knowing. First, these settings do not delete existing policies or ACLs. AWS says that if you later remove a Block Public Access setting, a bucket with a public policy or ACL becomes public again. Second, if your account sits under an AWS Organizations policy for Block Public Access, you cannot edit the account setting yourself.
Test before you block
Blocking public access can break a live site. If your website loads images straight from a bucket, turning on all four settings can make those images disappear. AWS says to verify your applications will work without public access before applying the settings. Check the bucket list first (next section), and make the change at a quiet time.
Check each bucket: policy, ACL and access points
Account-level settings are the safety net. You still need to know what each bucket allows. Open each bucket and look at its Permissions tab.
Bucket policy. Look for a statement with "Principal": "*" and "Effect": "Allow". That means anyone. AWS explains what counts as public in its meaning of public (opens in a new tab) section. Roughly, a policy is treated as non-public only if it grants access to fixed values such as a named account, role or a specific network.
ACL. AWS treats an ACL as public if it grants permission to the AllUsers or AuthenticatedUsers groups. Note that AuthenticatedUsers means any AWS account holder, not only your staff.
Object Ownership. This setting controls whether ACLs are in use. AWS says new buckets use Bucket owner enforced by default, which disables ACLs, and recommends keeping ACLs disabled for most uses. Older buckets may still have ACLs enabled, so check them.
Access points. If a bucket has access points, each can have its own policy. AWS notes that you cannot change an access point's Block Public Access settings after you create it.
Let AWS find the open ones
AWS provides a free review tool inside S3. Per the Access Analyzer for S3 page (opens in a new tab):
- In the IAM console, create an account-level analyzer in each Region where you have buckets. This step is required first.
- In the S3 console, choose General purpose buckets and expand the External access summary.
- Open the findings for a Region. Buckets under Public access findings can be reached by anyone on the internet. Cross-account access findings are shared with other AWS accounts.
- The Shared through column shows whether access comes from a bucket policy, a bucket ACL or an access point policy.
AWS says policy and ACL changes show up within 30 minutes, while changes to account-level settings can take up to 6 hours to appear. Access Analyzer for S3 is available at no extra cost in the S3 console.
If you want a read-only check from the command line, these two AWS CLI commands exist for it. Replace the placeholders with your own values.
aws s3control get-public-access-block --account-id YOUR_ACCOUNT_ID
aws s3api get-bucket-policy-status --bucket YOUR_BUCKET_NAME
Which buckets should be public and which never
A short rule of thumb works for most small businesses:
| Bucket holds | Public? | Better approach |
|---|---|---|
| Website images, CSS, JavaScript | Sometimes | Serve through CloudFront with origin access control |
| Customer uploads, ID documents, invoices | Never | Private, with short-lived download links created by your app |
| Backups, database exports, logs | Never | Private, with a narrow policy |
| Data shared with one partner | Not public | Name their account in the policy |
For website files, AWS's CloudFront guide recommends origin access control (OAC) over the older origin access identity. With OAC, the bucket stays private and only your CloudFront distribution can read it. AWS notes that a bucket set up as a website endpoint cannot use OAC. Here is the shape of the read-only bucket policy from that guide, with placeholders for your own values:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": { "Service": "cloudfront.amazonaws.com" },
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::YOUR_ACCOUNT_ID:distribution/YOUR_DISTRIBUTION_ID"
}
}
}
]
}
Fix: tighten, then test the app still works
Work in this order so you can undo each step.
- List what is public from the External access summary, and write down which app or person needs each one.
- Block Public Access on buckets that should never be public. In the bucket's Permissions tab, edit Block Public Access and turn on all four settings. Then test the app and the uploads and downloads that touch that bucket.
- Remove broad policy statements such as
Principal: *that you cannot explain. Replace them with named roles or accounts. - Move website files behind CloudFront with OAC, then turn Block Public Access on for that bucket too.
- Switch ACLs off by setting Object Ownership to Bucket owner enforced. AWS recommends checking your bucket policy covers all intended access first, because after ACLs are disabled, access is decided by policies alone.
- Archive findings only for buckets you meant to leave public. AWS lets you archive a finding to record that the access is intended.
- Turn on account-level Block Public Access once the buckets that need exceptions are sorted out.
If something breaks, AWS notes you can re-enable ACLs later and the old ACLs return. Keep a note of each change and its time.
Turn on logging and alerts
Logs tell you who read what, which matters most if a bucket was open. AWS's logging guide (opens in a new tab) says you can use server access logging, CloudTrail, or both, and that AWS recommends CloudTrail for bucket-level and object-level actions. It also lists that CloudTrail data events carry a fee, while management events' first delivery is free, so check the current price for your usage. Server access logs have no extra delivery cost beyond storage, but arrive within a few hours.
For alerts, treat the Access Analyzer findings as your warning list. Name one person who opens the External access summary on a set day, and check AWS's IAM Access Analyzer documentation for the notification options available in your account.
Repeat every quarter
Set a calendar reminder every three months and run through this list:
- Account-level Block Public Access is still on
- No new public findings in the External access summary
- Every bucket with an exception still has a reason and an owner
- New buckets use Bucket owner enforced
- Old buckets nobody uses are emptied and deleted
The same idea on Azure and Google Cloud
The names differ, but the idea is the same: turn off public access at the top level, then allow exceptions on purpose.
| Cloud | Setting | Where |
|---|---|---|
| Microsoft Azure | Storage account setting Allow Blob anonymous access, set to Disabled | Storage account, then Configuration under Settings |
| Google Cloud | Public access prevention, set to enforced on a bucket | Bucket setting, or the organisation policy constraint storage.publicAccessPrevention |
Per Microsoft's documentation (opens in a new tab), anonymous access is prohibited by default, and disallowing it at account level overrides each container's own setting. Google's public access prevention page (opens in a new tab) says it stops data being made public through IAM policies or ACLs, and a bucket is either enforced or inherited.
When to ask for a review
A single account is easy to check yourself. A review helps when you have many accounts, many Regions, unknown buckets that nobody can explain, or customer data in storage and no one has checked who can reach it.
Our cloud security review looks at storage permissions, access rights and logging in an account you own. You get findings ranked by risk, a clear fix for each, and a re-test after the fixes.
