DenCowboy
DenCowboy

Reputation: 15066

AWS S3 Bucket policies

I have created a bucket with cloudformation:

AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  BucketName:  
    Type: String
    Description: "Choose a name for the S3 Bucket"
    Default: "myrandomnameforbucket"
  S3Bucket:
    Type: "AWS::S3::Bucket"
    Properties:
      AccessControl: "Private"
      BucketName: !Ref BucketName

Now I'm writing a bucketPolicy but I'm facing some issues. What I want to achieve:

How can I achieve this? At the moment I denied a delete from userA and allowed an upload from userA.

          - Effect: Deny
            Principal:
              AWS: 
                !GetAtt UserA.Arn
            Action: "s3:DeleteObject"
            Resource: 
              Fn::Join:  ["", ["arn:aws:s3:::", Ref: "S3Bucket", "/*"]]
          - Effect: Allow
            Principal:
              AWS: 
                !GetAtt UserA.Arn
            Action: "s3:PutObject"
            Resource: 
              Fn::Join:  ["", ["arn:aws:s3:::", Ref: "S3Bucket", "/*"]]
          - Effect: Allow
            Principal: "?" # * is public?
            Action: s3:GetObject
            Resource: 
              Fn::Join:  ["", ["arn:aws:s3:::", Ref: "S3Bucket", "/*"]]

Upvotes: 0

Views: 792

Answers (2)

hansaplast
hansaplast

Reputation: 11573

I understand there are two questions:

  1. how to grant access to all IAM users when excluding anonymous users
  2. how to restrict one user more than the others, that is: removing rights you just granted to others

The first question sounds easy at first, as the documentation states:

In resource-based policies, use the Principal element to specify the accounts or users who are allowed to access the resource

So this would mean you could do something like:

Principal:
    AWS: !Ref "AWS::AccountId"

But when I tried it just didn't work. When setting the arn of a specific user it worked for me. This seems like a bug to me. Or an unclarity in the documentation. There is this other report I found.

Anyway, what you can do is to use Principal: AWS: "*" and then use a Condition to restrict to IAM users only.

The second question is much easier: policies are evaluated such that explicit denys have priority over general allows, see documentation.

The resulting policy can be e.g. written like this:

S3Policy:
  Type: "AWS::S3::BucketPolicy"
  Properties:
    Bucket: !Ref S3Bucket
    PolicyDocument:
      Statement:
        - Effect: Deny
          Action: "s3:DeleteObject"
          Resource: !Join ["", ["arn:aws:s3:::", Ref: "S3Bucket", "/*"]]
          Principal:
            AWS: !GetAtt UserA.Arn
        - Effect: Allow
          Action: "s3:PutObject"
          Resource: !Join ["", ["arn:aws:s3:::", Ref: "S3Bucket", "/*"]]
          Principal:
            AWS: !GetAtt UserA.Arn
        - Effect: Allow
          Action: ["s3:GetObject", "s3:DeleteObject"]
          Resource: !Join ["", ["arn:aws:s3:::", Ref: "S3Bucket", "/*"]]
          Principal:
            AWS: "*"
          Condition:
            StringEquals:
              "aws:PrincipalType": ["User"]

Upvotes: 1

marcincuber
marcincuber

Reputation: 3791

  {
"Version": "2012-10-17",
"Id": "S3PolicyId1",
"Statement": [
    {
        "Sid": "AllowGet",
        "Effect": "Allow",
        "Principal":{"AWS":"arn:aws:iam::account-number-without-hyphens:user/user1"},
        "Action": [
            "s3:Get*",
            "s3:List*"
        ],
        "Resource": [
            "arn:aws:s3:::s3_bucket_name",
            "arn:aws:s3:::s3_bucket_name/*"
        ]
    },
    {
        "Sid": "DenyDeleteObject",
        "Effect": "Deny",
        "Principal": {"AWS":"arn:aws:iam::account-number-without-hyphens:user/user1"},
        "Action": "s3:Delete*",
        "Resource": [
            "arn:aws:s3:::s3_bucket_name",
            "arn:aws:s3:::s3_bucket_name/*"
        ]
    },
    {
        "Sid": "Allow anyone in your account to access bucket",
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::account-number-without-hyphens:root"
        },
        "Action": [
            "s3:Get*",
            "s3:List*",
            "s3:Put*",
            "s3:Delete*"
        ],
        "Resource": [
            "arn:aws:s3:::s3_bucket_name",
            "arn:aws:s3:::s3_bucket_name/*"
        ]
    }
]

}

Here is a template in JSON format I quickly put together. My assumption here is that your group "ALL users (in my environment, nob public)" is everybody in the account. Hence, we define it in the third block. You can always manipulate the principal with whatever you want.

If you have any question please ask, I am happy to help.

Upvotes: 0

Related Questions