def lambda_handler()

in resource-compliance-lambda/handler.py [0:0]


def lambda_handler(event, context):
    # get account id
    account_id = context.invoked_function_arn.split(":")[4]
    # Need to make sure we don't waste time if the request type is
    # update or delete.  Exit gracefully
    if event['RequestType'] == "Delete":
        logger.info(f'Request Type is Delete; unsupported')
        cfnsend(event, context, 'SUCCESS', responsedata)
        return event
    if event['RequestType'] == "Update":
        logger.info(f'Request Type is Update; unsupported')
        cfnsend(event, context, 'SUCCESS', responsedata)
        return event

    # check if action provided in request
    if 'Action' in event['ResourceProperties']:

        action = (event['ResourceProperties']['Action']['Name'] if 'Name' in event['ResourceProperties']['Action']
                            else None)
        params = (event['ResourceProperties']['Action']['Parameters'] if action and 'Parameters' in event['ResourceProperties']['Action']
                            else None)

        # Convert tags provided as string in CFN to JSON format
        if 'json' == action.lower() and params:
            jObject = []
            keyList=[]
            sqsTags={}

            # Read tag string from paramter
            tags = (params['JSON'] if 'JSON' in params else '')
            type = (params['Type'] if 'Type' in params else None)

            logger.info(f'Processing tags: {tags}')

            try:
                # Convert string to JSON object
                for t in tags.split(','):
                    tg=None
                    k = t.split('=')
                    if len(k) != 2:
                        logger.info(f'No Key Value found in: '+t)
                        continue
                    if type.lower() == 'tags':
                        tg = {"Key":k[0], "Value":k[1]}
                        keyList.append(k[0])
                    elif type.lower() == 'dynamodbschema':
                        tg = {"AttributeName":k[0], "AttributeType":k[1]}
                    elif type.lower() == 'dynamodbkey':
                        tg = {"AttributeName":k[0], "KeyType":k[1]}
                    elif type.lower() == 'sqs':
                        sqsTags[k[0]] = k[1]

                    if tg:
                        jObject.append(tg)

            except Exception as e:
                logger.info(f'Error processing tags: {str(e)}')
                responsedata['error'] = str(e)
                cfnsend(event, context, 'FAILED', responsedata,'Error processing tags')
                return event

            # Validate if all require tags were provided
            if type.lower() == 'tags':
                for t in requireTags:
                    if not t in keyList:
                        # Failed CFN stack if missing require tag
                        logger.info(f'Missing require tag: {t}')
                        cfnsend(event, context, 'FAILED', responsedata,'Missing require tag: '+t)
                        return event

            # Add tags to SQS
            if type.lower() == 'sqs':
                queueURL = (params['SQS'] if 'SQS' in params else None)
                # Check if SQS URL provided
                if not queueURL:
                    # Failed CFN stack if missing SQS URL
                    logger.info(f'Missing SQS URI')
                    cfnsend(event, context, 'FAILED', responsedata,'Missing SQS URI')
                    return event

                # check if tags provided
                if not sqsTags:
                    # Failed CFN stack if missing tags
                    logger.info(f'Missing SQS tags')
                    cfnsend(event, context, 'FAILED', responsedata,'Missing SQS tags')
                    return event

                #add tags to sqs
                try:
                    logger.info(f'Add Tags to SQS: {queueURL}')
                    response = sqs.tag_queue(
                        QueueUrl=queueURL,
                        Tags=sqsTags
                    )
                except Exception as e:
                    logger.info(f'Error adding tag to SQS: {str(e)}')
                    responsedata['error'] = str(e)
                    cfnsend(event, context, 'FAILED', responsedata,'Error adding tags to SQS')
                    return event

            # response formated JSON object back to CFN
            responsedata['Json'] = jObject

        # put S3 notification to trigger lambda when new object created
        if 's3notification' == action.lower() and params:
            bucket_name = (params['Bucket'] if 'Bucket' in params else None)
            lambda_arn = (params['Lambda'] if 'Lambda' in params else None)
            filterRules = (params['FilterRules'] if 'FilterRules' in params else None)

            if bucket_name and lambda_arn:
                try:
                    response = lmd.add_permission(
                        Action='lambda:InvokeFunction',
                        FunctionName=lambda_arn,
                        Principal='s3.amazonaws.com',
                        SourceArn='arn:aws:s3:::'+bucket_name,
                        SourceAccount=account_id,
                        StatementId=str(uuid.uuid4())
                    )
                    bucket_notification = s3.BucketNotification(bucket_name)

                    if not filterRules:
                        response = bucket_notification.put(
                            NotificationConfiguration={
                                'LambdaFunctionConfigurations': [
                                    {
                                        'LambdaFunctionArn': lambda_arn,
                                        'Events': [
                                            's3:ObjectCreated:*'
                                        ]
                                    }
                                ]
                            }
                        )
                    else:
                        response = bucket_notification.put(
                            NotificationConfiguration={
                                'LambdaFunctionConfigurations': [
                                    {
                                        'LambdaFunctionArn': lambda_arn,
                                        'Events': [
                                            's3:ObjectCreated:*'
                                        ],
                                        'Filter': {
                                            'Key': {
                                                'FilterRules': filterRules
                                            }
                                        }
                                    }
                                ]
                            }
                        )
                    responsedata['Status']='SUCCESS'
                except Exception as e:
                    logger.info(f'Error processing S3 Notification: {str(e)}')
                    responsedata['error'] = str(e)
                    cfnsend(event, context, 'FAILED', responsedata,'Error processing S# Notification')
                    return event
            else:
                cfnsend(event, context, 'FAILED', responsedata,'S3 Notification - missing Bucket or Lambda paramters')
                return event

        # validate if kms is BYOK
        if 'byok' == action.lower() and params:
            key = (params['Key'] if 'Key' in params else None)
            # check if mks key provided
            if key:
                try:
                    # get information about kms key
                    response = kms.describe_key(
                        KeyId=key
                    )
                    # check if kms key is BYOK
                    if response['KeyMetadata']['Origin'] != 'EXTERNAL':
                        logger.info(f'BYOK No Found: {key}')
                        responsedata['Id'] = 'Provided Key is not BYOK'
                        cfnsend(event, context, 'FAILED', responsedata,'Provided Encryption Key is not BYOK')
                        return event
                except Exception as e:
                    logger.info(f'Error processing KMS: {str(e)}')
                    responsedata['error'] = str(e)
                    cfnsend(event, context, 'FAILED', responsedata,'Error processing KMS')
                    return event
            # Failed CFN stack if key not provided
            else:
                cfnsend(event, context, 'FAILED', responsedata,'No Encryption Key Provided')
                return event

        # validate if principal are not publicly open
        if 'principal' == action.lower() and params:
            accountid = (params['Account'] if 'Account' in params else None)
            principals = ((params['Principal']).split(',') if 'Principal' in params else None)
            type = (params['Type'] if 'Type' in params else None)

            if not accountid or not principals:
                # Failed CFN stack if account id or principal missing
                logger.info(f'Missing account id and/or principal')
                cfnsend(event, context, 'FAILED', responsedata,'Missing account id and/or principal')
                return event

            npList = []
            npstr = None
            if not type:
                for p in principals:
                    np = p
                    if p == "*":
                        np = accountid
                    if not np in npList:
                        npList.append(np)
                npstr = ','.join(npList)
            elif type == 'kms':
                for p in principals:
                    np = p.replace('{accountid}',accountid)
                    npList.append(np)

                npstr = npList

            # return formated principal back to CFN
            responsedata['Principal'] = npstr

    # Using the cfnsend function to format our response to Cloudforamtion and send it
    cfnsend(event, context, 'SUCCESS', responsedata)
    return event