Skip to content

Instantly share code, notes, and snippets.

@magnetikonline
Last active August 15, 2024 03:22
Show Gist options
  • Save magnetikonline/6215d9e80021c1f8de12 to your computer and use it in GitHub Desktop.
Save magnetikonline/6215d9e80021c1f8de12 to your computer and use it in GitHub Desktop.
AWS S3 bucket and IAM policy recipes.

AWS S3 bucket and IAM policy recipes

Recipes

Anonymous GET access

Type: bucket

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

Anonymous GET access - match HTTP referrer

Type: bucket

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "s3:GetObject",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME/*"
      ],
      "Condition": {
        "StringLike": {
          "aws:Referer": [
            "http://domain.com/*",
            "http://www.domain.com/*"
          ]
        }
      }
    }
  ]
}

Full access for specific IAM user/role

Type: bucket

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "s3:*",
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::ACCOUNT_ID:user/USERNAME_A",
          "arn:aws:iam::ACCOUNT_ID:user/USERNAME_B",
          "arn:aws:iam::ACCOUNT_ID:user/USERNAME_C",
          "arn:aws:iam::ACCOUNT_ID:role/ROLE_A",
          "arn:aws:iam::ACCOUNT_ID:role/ROLE_B",
          "arn:aws:iam::ACCOUNT_ID:role/ROLE_C"
        ]
      },
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME",
        "arn:aws:s3:::BUCKET_NAME/*"
      ]
    }
  ]
}

GET/PUT/DELETE access to specific path within a bucket

Type: user/group/role

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "s3:ListBucket",
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME"
      ]
    },
    {
      "Action": [
        "s3:DeleteObject",
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME/BUCKET_PATH/*"
      ]
    }
  ]
}

Note: The s3:ListBucket action against the bucket as a whole allows for the listing of bucket objects.

Restricted LIST & PUT/DELETE access to specific path within a bucket

Type: user/group/role

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "s3:ListBucket",
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME"
      ],
      "Condition": {
        "StringEquals": {
          "s3:delimiter": ["/"],
          "s3:prefix": ["","BUCKET_PATH/"]
        }
      }
    },
    {
      "Action": "s3:ListBucket",
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME"
      ],
      "Condition": {
        "StringLike": {
          "s3:prefix": ["BUCKET_PATH/BUCKET_SUB_PATH/*"]
        }
      }
    },
    {
      "Action": [
        "s3:DeleteObject",
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME/BUCKET_PATH/BUCKET_SUB_PATH/*"
      ]
    }
  ]
}

Note: This policy effectively provides protected user folders within an S3 bucket:

  • The first s3:ListBucket action allows listing only of objects at the bucket root and under BUCKET_PATH/.
  • The second s3:ListBucket action allows listing of objects from the path of BUCKET_PATH/BUCKET_SUB_PATH/ and below.
  • Technique is covered here under the heading Block 2: Allow listing objects in root and home folders.

Full access (and S3 console) for specific IAM users

Type: user/group/role

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "s3:ListAllMyBuckets",
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::*"
      ]
    },
    {
      "Action": "s3:*",
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME/*"
      ]
    }
  ]
}

Bucket and object delete deny

Type: bucket

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "s3:DeleteBucket",
      "Effect": "Deny",
      "Principal": "*",
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME"
      ]
    },
    {
      "Action": "s3:DeleteObject",
      "Effect": "Deny",
      "Principal": "*",
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME/*"
      ]
    }
  ]
}

Bucket enforce SSL requests only

Type: bucket

See: https://repost.aws/knowledge-center/s3-bucket-policy-for-config-rule

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "s3:*",
      "Effect": "Deny",
      "Principal": "*",
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME/",
        "arn:aws:s3:::BUCKET_NAME/*"
      ],
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      }
    }
  ]
}

CloudTrail log receive

Type: bucket

See: https://docs.aws.amazon.com/awscloudtrail/latest/userguide/create-s3-bucket-policy-for-cloudtrail.html

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "s3:GetBucketAcl",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME/*"
      ],
      "Condition": {
        "StringEquals": {
          "aws:SourceArn": "arn:aws:cloudtrail:AWS_REGION:AWS_ACCOUNT_ID:trail/TRAIL_NAME"
        }
      }
    },
    {
      "Action": "s3:PutObject",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME/AWSLogs/AWS_ACCOUNT_ID/*"
      ],
      "Condition": {
        "StringEquals": {
          "aws:SourceArn": "arn:aws:cloudtrail:AWS_REGION:AWS_ACCOUNT_ID:trail/TRAIL_NAME",
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    }
  ]
}

CloudFront origin access control (OAC) GET access

Type: bucket

See: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "s3:GetObject",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Resource": [
        "arn:aws:s3:::BUCKET_NAME/*"
      ],
      "Condition": {
        "StringEquals": {
          "aws:SourceArn": "arn:aws:cloudfront::AWS_ACCOUNT_ID:distribution/DISTRIBUTION_ID"
        }
      }
    }
  ]
}

Reference

@mariusa
Copy link

mariusa commented Aug 28, 2018

Thanks! Besides "GET/PUT/DELETE access to specific path within a bucket", how to do the same to keys containing a string, eg "user-profile" ?

@magnetikonline
Copy link
Author

That's a very good question @mariusa - one that I don't know is actually possible. What you're asking for are dynamic policies per IAM entity.

@zytek
Copy link

zytek commented Feb 21, 2019

Thanks.
I've started terraform recipes here: https://gist.github.com/zytek/f87db81ddce89523a7c4afd2516319a9

Policies are updated so AWS IAM Console won't complain about actions without resources etc.

@gheorghina
Copy link

gheorghina commented Jul 1, 2019

Hi

Do you know if there is a way to have the policies defined only in a S3 Bucket, not also on the IAM user or role if the bucket is defined on a different account ?

In my case, it seems it is not enough to have the policies set only on the bucket. It works only if I set the policies directly on the IAM users / roles which I use in the upload

Thanks

@magnetikonline
Copy link
Author

Hi, I have a similar need, to grant access on a bucket for a list of roles and users.
If I grant the access for the users - it is working, but for the roles it is not. Do you know if the roles need to also have some specific settings?

Thanks

Hey @gheorghina shouldn't be anything special, you would add the policy (from the template above) to a new role, then assign the role to EC2 compute/Lambda functions/etc. to which they should apply.

@gheorghina
Copy link

Hey thank you for the answer.
I figured it out my case. I write here, maybe it will help someone else at some point also.

My case is to copy an object from one bucket (from an Account A) to a different bucket( in an Account B).

In this case, the corresponding permissions have to be set:

  • in the IAM role or user which performs the copy action :
    - ListObject, GetObject, PutObject - from the source bucket
    - PutObject and PutObjectAcl for the destination bucket
  • in the destination bucket:
    - Allow PutObject and PutObjectAcl for the source account - set as Principal.

@magnetikonline
Copy link
Author

Nice one @gheorghina - i've had major pains with bucket -> bucket copies in the past.

The best advice I can give, always copy from a user/role in the target bucket account that can reach into the source. That way, you don't have to worry about getting ACL's correct on the new objects as they are placed into the target bucket.

I've had a few instances where I've not done this, and then the target bucket objects can't actually be read by account itself!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment