DEV Community

Shieldly
Shieldly

Posted on • Originally published at shieldly.io

Securing S3 Bucket Policies: Public Access, Conditions, and Common Mistakes

Originally published at shieldly.io/blog.

S3 bucket policies are written once and forgotten. They survive team changes, architecture pivots, and migration projects — and they accumulate permissions that nobody intended to leave open. S3 misconfigurations have been behind some of the largest cloud data breaches on record.

Why S3 Bucket Policies Matter

Bucket policies are resource-based policies attached to the bucket itself. They can grant access to principals that have no IAM permissions at all — including anonymous callers — if the policy allows it. A single misconfigured statement can override months of careful IAM work.

The Three Most Dangerous Patterns

1. Principal: * with no condition

{
  "Effect": "Allow",
  "Principal": "*",
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::my-bucket/*"
}
Enter fullscreen mode Exit fullscreen mode

An unconditioned wildcard principal means any AWS account, any IAM entity, and any unauthenticated caller can invoke the allowed actions. On a public S3 endpoint this is the open internet.

Fix: Add a condition — aws:PrincipalOrgID, aws:SourceArn, or aws:PrincipalArn:

{
  "Effect": "Allow",
  "Principal": "*",
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::my-bucket/*",
  "Condition": {
    "StringEquals": {
      "aws:PrincipalOrgID": "o-yourorgid123"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Missing s3:SecureTransport condition

Without aws:SecureTransport: true, the policy permits access over unencrypted HTTP. Credentials and data travel in plaintext. Add this to every Allow statement:

"Condition": {
  "Bool": {
    "aws:SecureTransport": "true"
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Overly broad Action grants

"Action": "s3:*"
Enter fullscreen mode Exit fullscreen mode

s3:* includes s3:DeleteObject, s3:PutBucketPolicy, and s3:DeleteBucket. A policy intended to share read access becomes a full-control grant. Replace with the exact actions needed:

"Action": ["s3:GetObject"]
Enter fullscreen mode Exit fullscreen mode

S3 Block Public Access Interaction

Block Public Access (BPA) settings at the account and bucket level override bucket policies. But they only block policies that grant access to Principal: * — a policy granting access to a specific external account bypasses BPA entirely. BPA is not a substitute for correct bucket policy authoring.

What a Secure Bucket Policy Looks Like

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/my-app-role"
      },
      "Action": ["s3:GetObject", "s3:PutObject"],
      "Resource": "arn:aws:s3:::my-bucket/*",
      "Condition": {
        "Bool": { "aws:SecureTransport": "true" }
      }
    },
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"],
      "Condition": {
        "Bool": { "aws:SecureTransport": "false" }
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Explicit principal, scoped actions, HTTPS enforced, deny-on-HTTP for belt-and-suspenders.


Analyze S3 bucket policies automatically — paste into Shieldly's free AI-Powered analysis. No signup, no credit card.

Launch offer: code 90Off2M — 90% off first 2 months. Pro from $1.90/mo. shieldly.io/pricing

Top comments (0)