Using AWS s3 Bucket Policies

February 26, 2018   

Introduction

If you have not been living in a dark disconnected cave for the past year, you may have noticed the growing trend of abusing badly configured Amazon s3 buckets for fun and profit. Using tools like Bucket Stream and Teh S3 Bucketeers for a short time you’ll see how bad the situation really is.

Check Your Bucket ACL and Bucket Policy

You can check your bucket ACL using the folowing command ( more info on AWS CLI )

$ aws s3api get-bucket-acl --bucket <bucket name>
And your bucket policy with
$ aws s3api get-bucket-policy --bucket <bucket name>

Spotting a Bad ACL

An example ACL that grants READ / WRITE otherwise known as FULL_CONTROL to anyone.

    {
      "Grantee": {
        "Type": "Group",
        "URI": "http://acs.amazonaws.com/groups/global/AllUsers"
      },
      "Permission": "FULL_CONTROL"
    }

An example ACL that grants READ / WRITE otherwise known as FULL_CONTROL to anyone with an AWS API key for any account.

    {
      "Grantee": {
        "Type": "Group",
        "URI": "http://acs.amazonaws.com/groups/global/AuthenticatedUsers"
      },
      "Permission": "FULL_CONTROL"
    }

An Example ACL that grants READ / READ_ACP to anyone (READ_ACP allows the grantee to view the ACL).

    {
      "Grantee": {
        "URI": "http://acs.amazonaws.com/groups/global/AllUsers",
        "Type": "Group"
      },
      "Permission": "READ"
    },
    {
      "Grantee": {
        "URI": "http://acs.amazonaws.com/groups/global/AllUsers",
        "Type": "Group"
      },
      "Permission": "READ_ACP"
    }

An Example ACL that grants WRITE / WRITE_ACP to anyone (WRITE_ACP allows the grantee to modify the ACL)

    {
      "Permission": "WRITE",
      "Grantee": {
        "URI": "http://acs.amazonaws.com/groups/global/AllUsers",
        "Type": "Group"
      }
    },
    {
      "Permission": "WRITE_ACP",
      "Grantee": {
        "URI": "http://acs.amazonaws.com/groups/global/AllUsers",
        "Type": "Group"
      }

An example ACL that grants READ / READ_ACP to anyone and WRITE / WRITE_ACP to anyone with an AWS API key for any account. I see this very often as AuthenticatedUsers is often mistook as meaning authenticated with this specific account

    {
      "Permission": "READ",
      "Grantee": {
        "URI": "http://acs.amazonaws.com/groups/global/AllUsers",
        "Type": "Group"
      }
    },
    {
      "Permission": "READ_ACP",
      "Grantee": {
        "URI": "http://acs.amazonaws.com/groups/global/AllUsers",
        "Type": "Group"
      },
      {
      "Permission": "WRITE",
      "Grantee": {
        "URI": "http://acs.amazonaws.com/groups/global/AuthenticatedUsers",
        "Type": "Group"
      },
      {
      "Permission": "WRITE_ACP",
      "Grantee": {
        "URI": "http://acs.amazonaws.com/groups/global/AuthenticatedUsers",
        "Type": "Group"
      }

Creating better permissions with a bucket policy

Creating a bucket policy may seem like a headache, but using the policy generator by Amazon you can have a solid permissions scheme in minutes.

Example:

Allow anyone to download any file from the /public/ directory as long as they know the URL, do not allow public listing of object names. My example will use a bucket named ‘ohtest123’

{
  "Id": "Policy123456789",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt123456789",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::ohtest123/public/*",
      "Principal": "*"
    }
  ]
}

I’m also using the default ACL which looks like this, the default ACL allows FULL_CONTROL to your AWS account.

{
  "Grants": [
    {
      "Permission": "FULL_CONTROL",
      "Grantee": {
        "DisplayName": "ExampleName",
        "ID": "abc123",
        "Type": "CanonicalUser"
      }
    }
  ],
  "Owner": {
    "DisplayName": "ExampleName",
    "ID": "abc123"
  }
}
Now if you visit the direct link to a file everything goes as planned, though if you visit the bucket root you will get access denied. Visiting /public will prompt you to download a 0 byte file due to the quirks of s3 object storage.

In a future article I’ll discuss policy to allow authenticated access to objects.