2
votes

I wrote a Python lambda function to check If my S3 Buckets are Public & Make them Private in my account. But i keep on getting an error:

({ "errorMessage": "'S3' object has no attribute 'put_bucket_access_block'", "errorType": "AttributeError", "stackTrace": [ " File \"/var/task/lambda_function.py\", line 66, in lambda_handler\n validate_instance(event)\n", " File \"/var/task/lambda_function.py\", line 32, in validate_instance\n addacl = s3_client.put_bucket_access_block(Bucket = s3_bucketName,\n", " File \"/var/runtime/botocore/client.py\", line 563, in getattr\n self.class.name, item)\n" ] })

Below is the Lambda function written in Python Boto3:

import boto3
from botocore.exceptions import ClientError
import json
import logging
import sys
log = logging.getLogger()
log.setLevel(logging.DEBUG)

log = logging.getLogger()
log.setLevel(logging.DEBUG)
print('Loading function')
sts_client = boto3.client('sts')
def validate_instance(rec_event):
    sns_msg = json.loads(rec_event['Records'][0]['Sns']['Message'])
    account_id = sns_msg['account']
    event_region = sns_msg['region']
    assumedRoleObject = sts_client.assume_role(
        RoleArn="arn:aws:iam::{}:role/{}".format(account_id, 'VSC-Admin-Account-Lambda-Execution-Role'),
        RoleSessionName="AssumeRoleSession1"
    )
    credentials = assumedRoleObject['Credentials']
    print(credentials)
    s3_client = boto3.client('s3', event_region, aws_access_key_id=credentials['AccessKeyId'],
                              aws_secret_access_key=credentials['SecretAccessKey'],
                              aws_session_token=credentials['SessionToken'],
                              )
    s3_bucketName = sns_msg['detail']['requestParameters']['bucketName']

    public_block = s3_client.put_public_access_block(Bucket = s3_bucketName,
            PublicAccessBlockConfiguration={
                'BlockPublicAcls': true,
                'IgnorePublicAcls':false,
                'BlockPublicPolicy':true,
                'RestrictPublicBuckets':true
                })        
    enableacl = s3_client.put_bucket_acl(Bucket = s3_bucketName,
                 ACL='private'
                 )


    put_public_access_block
    try:
        checkencryption=s3_client.get_bucket_encryption(Bucket=s3_bucketName)
        print("checking the encrytption")
        rules = checkencryption['ServerSideEncryptionConfiguration']['Rules']
        print('Bucket: %s, Encryption: %s' % (s3_bucketName, rules))
    except ClientError as e:
        if e.response['Error']['Code'] == 'ServerSideEncryptionConfigurationNotFoundError':
            response = s3_client.put_bucket_encryption(Bucket = s3_bucketName,
            ServerSideEncryptionConfiguration={
                'Rules': [
                    {
                        'ApplyServerSideEncryptionByDefault':{
                            'SSEAlgorithm': 'AES256'
                        }
                    },]
            })

        else:
            print("Bucket: %s, unexpected error: %s" % (s3_bucketName, e))


def lambda_handler(event, context):
    log.info("Here is the Received Event")
    log.info(json.dumps(event))
    validate_instance(event)
3
Unrelated to your posted question, the way you are supplying credentials in your Lambda function is not the best way to do this. Typically your Lambda function would be configured with a given IAM role and you would never have to explicitly supply boto3 with any credentials. Also, be aware that the version of boto3 available to you in the Lambda environment is not necessarily the latest available public version -- for more specifics, see docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.htmljarmod
Your error message no longer matches the code sample you have provided.John Rotenstein

3 Answers

1
votes

Rather than having to write code, you could simply activate Amazon S3 Block Public Access – Another Layer of Protection for Your Accounts and Buckets | AWS News Blog.

This allows you to simply block public access on a bucket, even if there are settings or a Bucket Policy that makes it public. It can even override object-level permissions if you wish.

1
votes

The problem is that the version of boto3 bundled with the Lambda Python runtime environment does not include this feature yet, hence put_public_access_block is not a method on the S3 client.

One workaround is to deploy your own Lambda layer that includes a later version of boto3 (that does support put_public_access_block). See related answer for options on including boto3 in a Lambda layer.

0
votes

You have the wrong method name. Change put_bucket_access_block to put_public_access_block.