S3 buckets have been the poster child for breaches and exposures that have been all over the news lately. As a result, most security teams have made detecting and securing open buckets a priority. In a recent blog post, we discussed how to secure S3 buckets in flight.

Today we will discuss how to prevent insider attacks on S3 buckets by restricting IAM access to follow least privilege model. Insider attacks have been gaining popularity as an attack on the rise. Read more about how to prevent insider threats here.

A good security practice for S3 buckets is to keep access restricted to the least privileges necessary and to ensure segregation of duties within your most sensitive DevOps processes. But, this gets tricky when you need to be agile and efficient with application deployments and at the same time, be consistently secure and compliant within the cloud. If internal buckets are accessible by the whole DevOps team, it helps your team to have less dependencies, however, it increases the odds of an insider threat or a potential compliance violation.

A typical approach in keeping your S3 buckets secure, would be to use a bucket policy and explicitly deny all Principals (which are IAM users and roles) that shouldn’t have access to the bucket. The challenge with this approach is the constant need to update bucket policy everytime there is a new user that you want to block.

 One workaround is to invert the logic and use NotPrincipal element in the bucket policy’s Deny statement which essentially is an explicit deny for any user that is not in the policy document. This has its own set of challenges (wildcard cannot be used) but you can use the Conditions parameter to whitelist specific users. For more information, refer to the AWS blog here.

How Dome9 Can Help:

Using Dome9’s easy and flexible syntax called Governance Specification Language(GSL) , you can quickly identify all the buckets that do not follow least privilege principle irrespective of which approach you’ve taken.

In the example below we would like to describe how Dome9 helps to identify all the buckets that do not follow the Least Privilege Principle (that is defined through Conditions element of the S3 Bucket Policy).

S3 Bucket Policy below is template policy that follows the principle of Least Privilege and includes the following criteria: Effect”: “Deny”, “Action”: “s3:*” and Condition.StringNotLike.aws:userId.

Sample Bucket Policy #1 we are testing against:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::MyExampleBucket",
        "arn:aws:s3:::MyExampleBucket/*"
      ],
      "Condition": {
        "StringNotLike": {
          "aws:userId": [
            "AROAEXAMPLEID:*",
            "AIDAEXAMPLEID",
            "111111111111"
          ]
        }
      }
    }
  ]
}

In order to identify all the S3 buckets that do not follow the Principle of the lease privilege we need to find the buckets that do not meet one of these specific criterias:

1. Effect”: “Deny”

2. “Action”: “s3:*”

3. Condition.StringNotLike.aws:userId

GSL code to find all the buckets that do not follow Sample Policy #1

S3Bucket should have policy.Statement contain [ Effect='Deny' and Action contain [ $ like 's3:%' ] and ( Condition.StringNotLike contain [aws:userid] ) ]

Now let’s assume that you have both Deny and Allow statements in your S3 Bucket Policy template.

S3 Bucket Policy below is template policy that follows the principle of Least Privilege and includes the required criteria: Effect”: “Allow”  Effect”:”Deny”, “Action”: “s3:*”, Principal.AWS contain [‘arn:aws:iam%’])] and Condition.StringNotLike.aws:userId.

Sample Bucket Policy #2 we are testing against:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111111111111:role/ROLENAME"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::MyExampleBucket"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111111111111:role/ROLENAME"
            },
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::MyExampleBucket/*"
        },
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::MyExampleBucket",
                "arn:aws:s3:::MyExampleBucket/*"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:userId": [
                        "AROAEXAMPLEID:*",
                        "111111111111"
                    ]
                }
            }
        }
    ]
}

 

GSL code to find all the buckets that do not follow Sample Policy #2

S3Bucket should have policy.Statement contain [Effect='Allow' and (Principal.AWS contain ['arn:aws:iam%'])] and policy.Statement contain [Effect='Deny' and (Action contain  ['s3:%']) and (Condition.StringNotLike contain [aws:userid]) ]

This is what the GSL results look like in Dome9:

You can further explore each entity in the Dome9 JSON editor view

Using Dome9 you can now restrict S3 bucket access to a specific IAM role or user easily and ensure your devops and application deployment teams can run fast and not break things!