S3 Bucket policies v.s. IAM policies

AWS’s Secured Storage Service (S3) is a service that allows authorized users to access and store objects in a globally uniquely named bucket. The permissions of an S3 bucket is controlled by AIM policies and Bucket policies.

In the article, we will briefly explore the differences between the two types of policies and follow up with an example of an S3 bucket that does the following:

  • Allows public anonymous ‘read-only’ access
  • Allow CURD permissions for specific AIM role

AIM policies

IAM policies define what a principal can do in your AWS environment. Unlike bucket policies, IAM policy does not require a “Principal” element because the principal is by default the entity that the IAM policy is attached to. This is the preferred way of controlling permissions to S3 buckets.

Bucket policies

S3 bucket policies are a special type of policy that is only associated with S3 buckets. The bucket policies specify the actions allowed or denied for the specified principal on the associated bucket. Generally, this type of policy is used to control the bucket access by individuals. IAM policies can achieve (almost all cases) the same permission controls as bucket policies.


There is a third type of access control for S3 buckets known as S3 ACL. This type of access control is a legacy feature and is not recommended. See source (end of this article) for details.

Public ‘read-only’ S3 bucket

Below shows the Terraform script used to create an S3 bucket that allows public ‘read-only’ access and CRUD permissions for users/services that has a specific ‘custom-api-role’ IAM role.

# create bucket with name 'some_bucket_name'
resource "aws_s3_bucket" "some-public-bucket" {
  bucket = "some_bucket_name"
  acl = "public-read"
  tags = {
    Name = "some_bucket_name"
    Classification = "PUBLIC"
# create IAM policy doc
data "aws_iam_policy_document" "policy-doc" {
  # Additional statement blocks can be found
  statement {
    effect = "Allow"
    actions = ["s3:*"]
    resources = [
# associate policy doc to iam policy
resource "aws_iam_policy" "custom-api-role-policy" {
  name   = "dev-custom-api-role"
  policy = "${data.aws_iam_policy_document.policy-doc.json}"
# Create iam role and allow api service (ecs-tasks AWS services) 
# to be granted assume role permissions
resource "aws_iam_role" "custom-api-role" {
  name = "custom-api-role"
  assume_role_policy = <<EOF
  "Version": "2008-10-17",
  "Statement": [
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
  "Service": "ecs-tasks.amazonaws.com"
# Attach the above policy to the role, giving S3.* actions to role
resource "aws_iam_role_policy_attachment" "attach-custom-api-role" {
  role = "${aws_iam_role.custom-api-role.name}"
  policy_arn = "${aws_iam_policy.custom-api-role-policy.arn}"

The below image shows the S3 bucket configuration created from running the above Terraform script.

Configurations of the Bucket created
No S3 Bucket policies are associated with the S3 Bucket.

IAM Policy simulator

The creator of the bucket is also the owner of the bucket. This can cause difficulty testing IAM policies, fortunately, AWS provides a policy simulator for testing IAM Policies using a simulator. Below shows an example of testing IAM policy for the created bucket:

IAM Policy simulator tool let you simulate policies and roles against existing infrastructures.

Source – Bucket, AIM and Bucket ACL in detail

Leave a Reply

Your email address will not be published. Required fields are marked *