3. S3 Bucket permission monitoring

Create config rule to monitor S3 bucket configuration changes

  • Sign in to the AWS Management Console and open the AWS Config console at Config Console
  • In the left navigation, choose Rules.
  • On the Rules page, choose Add rule.
  • Create rule to monitor public write permission for S3 bucket
    • Type write in the search bar to see the s3-bucket-public-write-prohibited rule.
    • Select s3-bucket-public-write-prohibited to add rule
    • Accept default rule parameters and click Save
    • One “Rules” page check that rule name s3-bucket-public-write-prohibited has been created
  • Create rule to monitor public write permission for S3 bucket
    • On the Rules page, choose Add rule.
    • Type read in the search bar to see the s3-bucket-public-read-prohibited rule.
    • Select s3-bucket-public-read-prohibited to add rule
    • Accept default rule parameters and click Save
    • On the Rules page check that rule name s3-bucket-public-read-prohibited has been created

Create new private S3 bucket

  • Sign in to the AWS Management Console and open the Amazon S3 console
  • Choose Create bucket
  • In the Bucket name (e.g. my-private-bucket) field, type a unique DNS-compliant name for your new bucket.
  • For Region, choose the region where you decided to run the workshop
  • Choose Create

Create IAM policy for Lambda function which will be used to remediate bucket ACL

  • Sign in to the AWS Management Console and open the IAM Console
  • Select Policy from left panel of IAM console and then select Create Policy
  • Select JSON. Delete default JSON policy and use the policy below
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "sns:Publish",
                "s3:GetBucketAcl",
                "logs:CreateLogGroup",
                "logs:PutLogEvents",
                "s3:GetBucketPolicy"
            ],
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "s3:PutBucketAcl",
                "s3:PutBucketPolicy",
                "s3:DeleteBucketPolicy"
            ],
            "Resource": "*"
        }
    ]
}
  • Click Review Policy
  • Provide Policy name s3-bucket-monitoring-lambda
  • Click Create Policy

Create IAM role for your Lambda function

  • On AWS IAM console, select Role from left panel
  • Select Create Role
  • Select Lambda from the list of services that will use this role and then select Next: Permission
  • In search box provide the policy name we created previously s3-bucket-monitoring-lambda
  • Select the check box next to the policy you created previously, s3-bucket-monitoring-lambda and then select Next: Review
  • Name your role LambdaS3BucketMonitoringRole and provide description
  • Select Create Role

Create Lambda function

  • In the AWS Management Console, under Services, select Lambda
  • From the Dashboard, select Create Function. and select Create Function button in the upper-right
  • On the Create function page Choose Author from scratch
  • Provide a name for the function. We’re using S3BucketPermissionResponder
  • In the Runtime dropdown list, select Python 3.6 as our lambda function in in python
  • Under Role, select Choose an existing role. Select LambdaS3BucketMonitoringRole and then select Create function
  • On function Configuration page, scroll down to Basic settings and change Timeout value to 50 sec
  • Scroll up to the Designer section and select the name of your Lambda function and use the following code
import boto3
from botocore.exceptions import ClientError
import json
import os


ACL_RD_WARNING = "The S3 bucket ACL allows public read access."
PLCY_RD_WARNING = "The S3 bucket policy allows public read access."
ACL_WRT_WARNING = "The S3 bucket ACL allows public write access."
PLCY_WRT_WARNING = "The S3 bucket policy allows public write access."
RD_COMBO_WARNING = ACL_RD_WARNING + PLCY_RD_WARNING
WRT_COMBO_WARNING = ACL_WRT_WARNING + PLCY_WRT_WARNING
RD_WRT_COMBO_WARNING = RD_COMBO_WARNING + WRT_COMBO_WARNING


def policyUpdate(bucketName, s3):
 # instantiate Amazon S3 client
    s3 = boto3.client('s3')
    s3.delete_bucket_policy(Bucket=bucketName)
     

def lambda_handler(event, context):
    # instantiate Amazon S3 client
    s3 = boto3.client('s3')
    resource = list(event['detail']['requestParameters']['evaluations'])[0]
    bucketName = resource['complianceResourceId']
    
    complianceFailure = event['detail']['requestParameters']['evaluations'][0]['annotation']
    if(complianceFailure == ACL_RD_WARNING or complianceFailure == ACL_WRT_WARNING):
        s3.put_bucket_acl(Bucket = bucketName, ACL = 'private')
        print ("Remediating S3 bucket -",bucketName,". Removing public read/write permission from ACL")
    elif(complianceFailure == PLCY_RD_WARNING  or complianceFailure == PLCY_WRT_WARNING):
        policyUpdate(bucketName, s3)
        print ("Remediating S3 bucket -",bucketName,". Removing public read/write permission from Bucket Policy")
    elif(complianceFailure == RD_COMBO_WARNING or complianceFailure == WRT_COMBO_WARNING):
        s3.put_bucket_acl(Bucket = bucketName, ACL = 'private')
        policyUpdate(bucketName, s3)
        print ("Remediating S3 bucket -",bucketName,". Removing public read/write permission from ACL or Bucket Policy")
    elif(complianceFailure == RD_WRT_COMBO_WARNING):
        s3.put_bucket_acl(Bucket = bucketName, ACL = 'private')
        policyUpdate(bucketName, s3)
        print ("Remediating S3 bucket -",bucketName,". Removing public read/write permission from ACL and Bucket Policy")
   
    return 0  # done

Create and Configure a CloudWatch Rule to detect event and trigger remediation

  • In the AWS Management Console, under Services, select CloudWatch
  • On the left-hand side, under Events, select Rules
  • Click Create rule
  • Under Event Source, select the dropdown list and select Custom event pattern
  • Copy the following pattern CloudWatch Code

Note: Update the pattern with the name of S3 bucket

{
  "source": [
    "aws.config"
  ],
  "detail": {
    "requestParameters": {
      "evaluations": {
        "complianceResourceId": [
          "your bucket name"
        ],
        "complianceType": [
          "NON_COMPLIANT"
        ]
      }
    },
    "additionalEventData": {
      "managedRuleIdentifier": [
        "S3_BUCKET_PUBLIC_READ_PROHIBITED",
        "S3_BUCKET_PUBLIC_WRITE_PROHIBITED"
      ]
    }
  }
}
  • Add trigger for remediation by selecting Add Target

Verify it works

  • In the AWS Management Console, under Services, select S3
  • Select your S3 bucket we created earlier
  • Select Permission tab
  • Change Public access permission for Group Everyone to List objects for everyone - refer screen shot below
  • Now you can see that bucket is public and Public is displayed under Permission in Permission Tab bucket now has public access. After several minutes, the AWS Config Dashboard notes that there is one non-compliant resource.

Please note that if you have any buckets previously configured as public read/write all of them will be listed in config rule as non compliant

After 5-10 minutes, In the Amazon S3 Console, we can see that the bucket no longer has public listing of objects enabled after the invocation of the Lambda function triggered by the CloudWatch Rule created earlier