Introduction

Securing the objects stored in Amazon S3 (Simple Storage Service) is crucial for protecting sensitive data. When it comes to implementing access control, there are two commonly used methods: Bucket Policies and Access Control Lists (ACLs). These mechanisms allow administrators to define fine-grained permissions for their S3 buckets and the objects within. In this blog post, we will explore the differences between Bucket Policies and ACLs, how they function, and when it’s appropriate to use each.

Access Control List (ACL)

Access Control Lists (ACLs) in Amazon S3 provided a way to control access to individual objects within a bucket. They allowed you to specify granular permissions for different AWS accounts or groups, granting or revoking access at the object level. ACLs were used to supplement the access control provided by Bucket Policies, which operated at the bucket level.

ACLs consist of two types: Canned ACLs and Custom ACLs. Canned ACLs were predefined sets of permissions that made it easy to grant common types of access, such as private, public-read, and public-read-write. Custom ACLs provided the flexibility to define specific permissions for individual AWS accounts or groups.

When setting up an ACL for an object, you can specify different permissions for the object owner, the bucket owner, individual AWS accounts, or groups. The permissions include read, write, read ACP (Access Control Policy), write ACP, and full control. This allowed you to grant or revoke specific permissions for different entities.

To illustrate how ACLs work, here are a few examples:

  1. Granting public access to a specific object: You could set the ACL of an object to “public-read” to make it publicly accessible, even if the bucket policy restricts public access. This could be useful for hosting static website assets or publicly available files.
  2. Revoking access to a specific object: If you needed to remove access to a specific object without modifying the bucket policy, you could set the ACL to “private” or remove the permission for the desired AWS account or group. This gave you the flexibility to manage access to individual objects separately from the overall bucket policy.
  3. Granting temporary access to an object: By modifying the ACL, you could provide temporary access to an object to a specific AWS account or IAM user. This could be useful for sharing files with limited-time access or granting specific individuals or services permission to perform actions on an object for a specific duration.

However, ACLs have been deprecated in favor of Bucket Policies. This decision was made to simplify access control and to provide a more consistent and scalable approach. Bucket Policies offer more flexibility and granularity, allowing you to define access permissions at the bucket level and control who can perform specific actions on objects within the bucket.

You should only consider using ACLs if you need control access for each object individually which should be a rare scenario.

Example

Granting read access to an AWS account

<AccessControlPolicy>
    <Owner>
        <ID>OWNER_ID</ID>
        <DisplayName>OWNER_NAME</DisplayName>
    </Owner>
    <AccessControlList>
        <Grant>
            <Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
                <ID>ACCOUNT_ID</ID>
                <DisplayName>ACCOUNT_NAME</DisplayName>
            </Grantee>
            <Permission>READ</Permission>
        </Grant>
    </AccessControlList>
</AccessControlPolicy>

In this example, the ACL grants read access to a specific AWS account identified by its account ID. The Permission element is set to READ, allowing the account to read the object.

Granting full control to an IAM group:

<AccessControlPolicy>
    <Owner>
        <ID>OWNER_ID</ID>
        <DisplayName>OWNER_NAME</DisplayName>
    </Owner>
    <AccessControlList>
        <Grant>
            <Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Group">
                <URI>http://acs.amazonaws.com/groups/global/GROUP_NAME</URI>
            </Grantee>
            <Permission>FULL_CONTROL</Permission>
        </Grant>
    </AccessControlList>
</AccessControlPolicy>

In this example, the ACL grants full control to an IAM group identified by its group name. The Permission element is set to FULL_CONTROL, allowing the group to perform any action on the object.

Bucket Policies

A Bucket Policy is a JSON-based access policy that can be attached to an S3 bucket. It allows you to define access permissions at the bucket level and control who can perform specific actions on the objects within the bucket. Bucket Policies are commonly used to provide cross-account access, set up IP-based restrictions, and manage access for AWS services like CloudFront.

Anatomy of a Bucket Policy

A Bucket Policy consists of a set of statements, where each statement defines a specific permission or condition. The key components of a Bucket Policy statement include:

  • Principal: Specifies the AWS account or IAM user/group to which the statement applies.
  • Effect: Determines whether the statement allows or denies access.
  • Action: Defines the specific S3 actions that are allowed or denied.
  • Resource: Specifies the Amazon Resource Name (ARN) of the targeted S3 bucket or object.
  • Condition: Optional element that allows you to further refine access based on factors such as IP ranges or request headers.

Use Cases for Bucket Policies

Bucket Policies are best suited for scenarios that require fine-grained access control at the bucket level. Here are some common use cases:

  • Cross-account access: With Bucket Policies, you can grant or deny access to specific AWS accounts, allowing other accounts to perform actions on your bucket or its objects.
  • IP-based restrictions: You can use Bucket Policies to restrict access to your bucket from specific IP addresses or ranges.
  • Access control for AWS services: Bucket Policies can be leveraged to allow AWS services, such as CloudFront, to directly access your S3 bucket.

Examples

Granting read access to a specific AWS account:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "GrantReadAccess",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::ACCOUNT_ID:root"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::BUCKET_NAME/*"
        }
    ]
}

In this example, the Bucket Policy grants read access to a specific AWS account identified by its account ID. The Principal element specifies the account using its ARN (Amazon Resource Name). The Action element is set to s3:GetObject, allowing the account to retrieve objects from the bucket. The Resource element defines the ARN of the bucket and specifies that the permission applies to all objects in the bucket.

Denying write access to a specific IP range:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyWriteAccess",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::BUCKET_NAME/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "192.168.0.0/24"
                }
            }
        }
    ]
}

In this example, the Bucket Policy denies write access to a specific IP range. The Principal element is set to *, meaning the policy applies to all AWS accounts. The Action element is set to s3:PutObject, which allows writing objects to the bucket. The Resource element defines the ARN of the bucket and specifies that the permission applies to all objects in the bucket. The Condition element restricts access to requests originating from the IP range 192.168.0.0/24.

Conclusion

In conclusion, securing your Amazon S3 (Simple Storage Service) objects requires careful consideration of access control methods. While both Bucket Policies and Access Control Lists (ACLs) offer ways to define fine-grained permissions, Bucket Policies are generally recommended due to their increased flexibility, scalability, and consistency.

Bucket Policies operate at the bucket level, allowing you to define access permissions for entire buckets and control who can perform specific actions on objects within them. This makes them ideal for scenarios that require comprehensive access control at the bucket level, such as cross-account access, IP-based restrictions, and granting access to AWS services.

On the other hand, ACLs provide granular permissions for individual objects within a bucket. However, Bucket Policies are now recommended for managing access to S3 buckets.

While there may be rare scenarios where ACLs are necessary, such as when you need to control access on a per-object basis, the overall trend is to use Bucket Policies for consistent and scalable access control.