S3 bucket policy uses wildcard principals

Limit the actions, resources, and conditions of wildcard principals in S3 bucket policies, and review Block Public Access to prevent unnecessary access.

Description

A wildcard Principal in an S3 bucket policy targets a broad set of principals. Without appropriate restrictions, an Allow statement can let unintended principals perform the specified actions. Effective permissions depend on actions, resources, conditions, explicit denies, and S3 Block Public Access.

Conditions such as a fixed organization or IP range can restrict access, so a wildcard alone does not mean that every internet request is allowed. Check whether the restrictions meet the actual requirements. A need for public reads does not justify public writes or deletions.

Potential impact

  • Unnecessary read permissions can expose object contents or lists of objects in the bucket, depending on the permitted actions and resources.
  • Write or deletion permissions can allow object changes, data loss, or service disruption.
  • Relaxing conditions or Block Public Access can broaden the access granted by an existing policy.

Remediation

  • Limit permissions to the required principals, actions, and bucket or object ARNs. If wildcards are necessary, use valid conditions that keep access sufficiently narrow.
  • Review all allows and denies, ACLs, and Block Public Access together. Test approved requests and requests that should be denied.
  • Apply the policy using the appropriate provider and module configuration, and inspect terraform plan. Version 3.7.0 of terraform-aws-modules/s3-bucket/aws requires attach_policy = true to apply a custom policy.

Examples

These partial examples compare an allow and a deny with an IP condition. Define aws_s3_bucket.example separately, and replace the documentation IP address with the required source address. Do not apply both policies to the same bucket at once.

Allow with an IP condition

hcl
resource "aws_s3_bucket_policy" "public_policy" {
  bucket = aws_s3_bucket.example.id

  policy = <<POLICY
{
  "Version": "2012-10-17",
  "Id": "MYBUCKETPOLICY",
  "Statement": [
    {
      "Sid": "IPAllow",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "s3:*",
      "Resource": "${aws_s3_bucket.example.arn}/*",
      "Condition": {
         "IpAddress": {"aws:SourceIp": "203.0.113.10/32"}
      }
    }
  ]
}
POLICY
}

For requests meeting aws:SourceIp, this permits the broad set of S3 actions applicable to the object resources. It is not an unconditional grant to every source, but permissions should still be narrowed to the principals and actions needed from that source.

Explicit deny with an IP condition

hcl
resource "aws_s3_bucket_policy" "restricted_policy" {
  bucket = aws_s3_bucket.example.id

  policy = <<POLICY
{
  "Version": "2012-10-17",
  "Id": "MYBUCKETPOLICY",
  "Statement": [
    {
      "Sid": "IPDeny",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": "${aws_s3_bucket.example.arn}/*",
      "Condition": {
         "IpAddress": {"aws:SourceIp": "203.0.113.10/32"}
      }
    }
  ]
}
POLICY
}

This explicitly denies only requests that meet the same IP condition. It does not block other source addresses and may deny legitimate users too. Design the complete policy around the permissions that are actually required.

References