RSTR-IAC-009 — S3 bucket with public ACL

Summary

A Terraform aws_s3_bucket (or aws_s3_bucket_acl) sets acl = "public-read" or acl = "public-read-write". Every object in the bucket is now readable (and, with the second form, writable) by every IPv4 address on the public internet.

Public buckets are the single most common AWS data-leak vector because the field is one line of HCL away from "private". AWS itself ships four separate guardrails to make it harder (Block Public Access settings, IAM analyzer, security-hub findings, bucket policy explicit-deny rules) — rastray is the same fence at the IaC layer.

Severity

High.

Languages

Terraform (.tf, .tfvars).

What rastray flags

resource "aws_s3_bucket" "assets" {
  bucket = "my-org-assets"
  acl    = "public-read"             # ← flagged
}
resource "aws_s3_bucket_acl" "assets" {
  bucket = aws_s3_bucket.assets.id
  acl    = "public-read-write"       # ← flagged
}

What rastray deliberately does not flag

  • acl = "private" (default).
  • acl = "authenticated-read" — limited to any AWS account, which is a separate (smaller) blast radius and is occasionally intentional for cross-account delivery.
  • acl = "bucket-owner-full-control" — required pattern for cross-account object writes.

How to fix it

  1. Switch the ACL to "private".

  2. If you need public delivery, front the bucket with CloudFront and an origin access identity:

    resource "aws_s3_bucket" "assets" {
      bucket = "my-org-assets"
      acl    = "private"
    }
    
    resource "aws_cloudfront_distribution" "cdn" {
      origin {
        domain_name = aws_s3_bucket.assets.bucket_regional_domain_name
        origin_id   = "s3-assets"
        s3_origin_config {
          origin_access_identity = aws_cloudfront_origin_access_identity.oai.cloudfront_access_identity_path
        }
      }
      # ...
    }
    
  3. Add aws_s3_bucket_public_access_block with all four flags set to true — it's a no-cost belt-and-braces:

    resource "aws_s3_bucket_public_access_block" "assets" {
      bucket                  = aws_s3_bucket.assets.id
      block_public_acls       = true
      block_public_policy     = true
      ignore_public_acls      = true
      restrict_public_buckets = true
    }
    

References