How to test an S3 bucket policy before you deploy it
A bucket policy is evaluated on every request to the bucket, so a single wrong line can expose data to the internet or lock your own applications out. This walkthrough shows how to review a policy quickly, using the samples above.
Step 1: Check who is allowed in (Principal)
Load the Public bucket sample. Its statement has "Effect": "Allow" with "Principal": "*", which means anyone on the internet. That is only correct for a deliberately public static website, and even then it should allow nothing beyond s3:GetObject. For everything else, name the principals: an account (arn:aws:iam::111122223333:root), a role, or a service such as cloudfront.amazonaws.com.
Step 2: Check what they can do (Action)
Load Wildcard actions. "Action": "s3:*" grants every S3 permission, including s3:DeleteObject, s3:PutBucketPolicy and s3:DeleteBucket. Replace it with only the actions the caller needs: usually s3:GetObject to read, plus s3:PutObject to write and s3:ListBucket to list.
Step 3: Match actions to the right resource
This is the most common reason a "correct" policy still returns AccessDenied. Bucket-level actions such as s3:ListBucket apply to the bucket ARN (arn:aws:s3:::my-bucket). Object-level actions such as s3:GetObject apply to objects (arn:aws:s3:::my-bucket/*). A statement that lists both actions against only one ARN silently grants half of what you intended.
Step 4: Add guard conditions
Load Secure policy to see the patterns worth copying:
- Deny non-TLS access: a Deny statement with
"Condition": {"Bool": {"aws:SecureTransport": "false"}}. - Limit to your organization:
aws:PrincipalOrgID, so a leaked role in an unknown account can't use the bucket. - Limit by network:
aws:SourceVpcefor VPC endpoint access, oraws:SourceIpfor fixed office ranges.
Step 5: Cross-account access needs both sides
Load Cross-account. Granting another account in the bucket policy is only half the setup: the role in the other account also needs an IAM policy that allows the same actions on your bucket. If objects are encrypted with a customer-managed KMS key, that key's policy must allow the other account too. Otherwise reads fail even with a perfect bucket policy.
Common mistakes this check catches
"Principal": "*"with Allow and no condition: public access.s3:*ors3:Put*granted to applications that only read.NotPrincipalwith Allow, which grants access to everyone except the listed principals.- Bucket and object ARNs mixed up, as in Step 3.
- No TLS-only Deny statement.
Is the bucket actually public?
Amazon S3 decides "public" with its own rule: an Allow to "Principal": "*" is public unless a condition limits it to fixed values of keys such as aws:PrincipalOrgID, aws:SourceVpce, aws:SourceVpc, aws:SourceArn, aws:SourceAccount or a narrow aws:SourceIp range. aws:SecureTransport does not make a statement private. The Effective access box uses that rule and the bucket settings you enter:
- RestrictPublicBuckets on: S3 ignores public grants for anyone outside your account (AWS services still work).
- BlockPublicPolicy on: S3 refuses to save a public policy.
- Object Ownership = Bucket owner enforced: ACLs are off, so only policies grant access. This is the default for new buckets since April 2023.
Encryption at rest no longer needs a policy: since January 2023 Amazon S3 encrypts every new object with SSE-S3 by default. Use bucket default encryption if you need SSE-KMS.
The templates give known-good starting points (CloudFront with Origin Access Control, Amazon Connect prompts, access logs, CloudTrail, cross-account read-only, organisation-only, VPC endpoint only), and the one-click fixes add an HTTPS-only Deny, TLS 1.2, aws:SourceAccount for service principals, or the missing bucket or object ARN — with a preview before anything changes.
Before you apply it
- Keep S3 Block Public Access on at the account level unless the bucket must be public. It overrides public grants in bucket policies.
- Validate with IAM Access Analyzer policy checks, which run in the console when you edit the policy and through the
ValidatePolicyAPI. - Test with a real call from each principal:
aws s3 ls s3://my-bucketandaws s3 cp.
For identity-side policies, the IAM Policy Simulator and Policy Generator cover the other half of the permission check.