Locking Down Your S3 Buckets With Terraform

Every time I hear about a company’s critical data being left exposed on the internet, I start thinking about my S3 buckets. I recently started creating some buckets with Terraform and realized acl = "private" isn’t as private as we would like. With that setting it’s still possible for objects to be put into the bucket with less restrictive ACLs. You know you only have "private" set when you see the text “Objects can be public” next to the bucket in the console.

To lock down your bucket, you’ll want to use the aws_s3_bucket_public_access_block resource. The full details can be found in the AWS S3 Block Public Access documentation. Here’s a full Terraform example:

resource "aws_s3_bucket" "private-bucket" {
  bucket = "private-bucket-sample"
  acl = "private"
}

resource "aws_s3_bucket_public_access_block" "private-bucket-public-access-block" {
  bucket = aws_s3_bucket.private-bucket.id
  block_public_acls = true
  block_public_policy = true
  ignore_public_acls = true
  restrict_public_buckets = true
}

When you’ve applied that block, you should see “Bucket and objects not public” next to your bucket in the console.

If you need public access to your S3 objects use CloudFront or maybe signed URLs. If you really must have public S3 objects, I would suggest moving that data to a separate AWS account. It’s pretty easy to manage multiple AWS accounts these days and having a separate account for your public bucket makes a lot of sense.