S3 bucket policies and ACLs should not be configured for public read access

Description

S3 bucket policies and ACLs should not be configured for public read access. It is a security risk for a bucket to have an ACL or bucket policy that is configured for public read access, even if the bucket itself is not currently public. A bucket configured for public read access can potentially be made public, allowing any AWS user or anonymous user to access the data in it.

Remediation Steps

AWS Console

  • Navigate to S3.

  • Select the S3 bucket.

  • Select Permissions > Access Control List.

  • In Public access, select Everyone and uncheck:

    • List objects

    • Write objects

    • Read bucket permissions

    • Write bucket permissions

  • Click Save.

  • Navigate to S3.

  • In the left navigation, select Block public access (account settings).

  • Click Edit.

  • Check the Block all public access checkbox.

  • Click Save Changes.

  • Enter confirm and click confirm.

AWS CLI

To make an S3 bucket not publicly accessible:

aws s3api put-bucket-acl \
    --bucket fugue-bucket-example --acl private
aws s3api put-public-access-block \
    --bucket fugue-bucket-example \
    --public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"

CloudFormation

JSON

{
  "Properties" : {
    "PublicAccessBlockConfiguration" : {
      "BlockPublicAcls" : true,
      "BlockPublicPolicy" : true,
      "IgnorePublicAcls" : true,
      "RestrictPublicBuckets" : true
    }
  }
}
JSON Example Configuration
{
  "Type" : "AWS::S3::Bucket",
  "Properties" : {
    "PublicAccessBlockConfiguration" : {
      "BlockPublicAcls" : true,
      "BlockPublicPolicy" : true,
      "IgnorePublicAcls" : true,
      "RestrictPublicBuckets" : true
      }
    }
  # other required fields here
}

YAML

Properties:
  PublicAccessBlockConfiguration:
    BlockPublicAcls: true
    BlockPublicPolicy: true
    IgnorePublicAcls : true
    RestrictPublicBuckets : true
YAML Example Configuration
Type: AWS::S3::Bucket
Properties:
  PublicAccessBlockConfiguration:
    BlockPublicAcls: true
    BlockPublicPolicy: true
    IgnorePublicAcls : true
    RestrictPublicBuckets : true
# other required fields here

Terraform

  • Ensure that the aws_s3_bucket acl field does NOT contain EITHER of the following:

    • “public-read”

    • “public-read-write”

  • Ensure that the grant block does NOT contain BOTH an invalid uri and permissions field:

  • If a bucket policy is defined in the bucket’s policy field, ensure the JSON document does NOT contain BOTH an invalid principal, an invalid action, and an invalid effect:

    • Invalid principals:

      • "Principal": { "AWS": "*" }

      • "Principal": "*"

    • Invalid actions:

      • "*"

      • "s3:*"

      • "s3:List*"

      • "s3:Get*"

      • "s3:ListBucket*"

      • "s3:GetObject*"

      • "s3:ListBucket"

      • "s3:ListBucketVersions"

      • "s3:ListBucketMultipartUploads"

      • "s3:GetObject"

      • "s3:GetObjectVersion"

      • "s3:GetObjectTorrent"

    • Invalid effect:

      • "Effect": "Allow"

  • If a bucket policy as defined as an aws_s3_bucket_policy, ensure the JSON document in the policy field does NOT contain BOTH an invalid principal, an invalid action, and an invalid effect, as listed above

  • While a aws_s3_bucket_public_access_block is not required for the bucket, it’s highly recommended. Ensure the following aws_s3_bucket_public_access_block fields are all set to true:

    • block_public_acls

    • block_public_policy

    • ignore_public_acls

    • restrict_public_buckets

Example Configuration

# Compliant ACL
resource "aws_s3_bucket" "b" {
  acl    = "private"
  # other required fields here
}
# Compliant grant
resource "aws_s3_bucket" "bucket" {
  bucket = "mybucket"

  grant {
    id          = data.aws_canonical_user_id.current_user.id
    type        = "CanonicalUser"
    permissions = ["FULL_CONTROL"]
  }

  # other required fields here
}
# Compliant bucket policy
resource "aws_s3_bucket" "b" {
  bucket = "my-tf-test-bucket"
  # other required fields here
}

resource "aws_s3_bucket_policy" "b" {
  bucket = aws_s3_bucket.b.id

  policy = jsonencode({
    Version = "2012-10-17"
    Id      = "MYBUCKETPOLICY"
    Statement = [
      {
        Sid       = "IPAllow"
        Effect    = "Deny"
        Principal = "*"
        Action    = "s3:*"
        Resource = [
          aws_s3_bucket.b.arn,
          "${aws_s3_bucket.b.arn}/*",
        ]
        Condition = {
          NotIpAddress = {
            "aws:SourceIp" = "8.8.8.8/32"
          }
        }
      },
    ]
  })

  # other required fields here
}
# Compliant bucket public access block
resource "aws_s3_bucket" "b" {
  # other required fields here
}

resource "aws_s3_bucket_public_access_block" "private" {
  bucket                  = "${aws_s3_bucket.b.id}"
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}