def test_collector(historical_role, mock_lambda_environment, historical_sqs, security_groups, current_security_group_table): from historical.security_group.models import CurrentSecurityGroupModel from historical.security_group.collector import handler event = CloudwatchEventFactory(detail=DetailFactory( requestParameters={'groupId': security_groups['GroupId']}, eventName='CreateSecurityGroup'), ) data = json.dumps(event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, None) assert CurrentSecurityGroupModel.count() == 1 event = CloudwatchEventFactory(detail=DetailFactory( requestParameters={'groupId': security_groups['GroupId']}, eventName='DeleteSecurityGroup'), ) data = json.dumps(event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, None) assert CurrentSecurityGroupModel.count() == 0
def test_collector(historical_role, buckets, mock_lambda_environment, swag_accounts, current_s3_table): from historical.s3.collector import handler now = datetime.utcnow().replace(tzinfo=None, microsecond=0) create_event = CloudwatchEventFactory( detail=DetailFactory(requestParameters={"bucketName": "testbucket1"}, source="aws.s3", eventName="CreateBucket", eventTime=now)) data = json.dumps(create_event, default=serialize) data = KinesisRecordsFactory( records=[KinesisRecordFactory(kinesis=KinesisDataFactory(data=data))]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, None) result = list(CurrentS3Model.query("arn:aws:s3:::testbucket1")) assert len(result) == 1 # Verify that the tags are duplicated in the top level and configuration: assert len(result[0].Tags.attribute_values) == len( result[0].configuration.attribute_values["Tags"]) == 1 assert result[0].Tags.attribute_values["theBucketName"] == \ result[0].configuration.attribute_values["Tags"]["theBucketName"] == "testbucket1" # noqa # Polling (make sure the date is included): polling_event = CloudwatchEventFactory( detail=DetailFactory(requestParameters={ "bucketName": "testbucket1", "creationDate": now }, source="aws.s3", eventName="DescribeBucket", eventTime=now)) data = json.dumps(polling_event, default=serialize) data = KinesisRecordsFactory( records=[KinesisRecordFactory(kinesis=KinesisDataFactory(data=data))]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, None) assert CurrentS3Model.count() == 1 # Load the config and verify the polling timestamp is in there: result = list(CurrentS3Model.query("arn:aws:s3:::testbucket1")) assert result[0].configuration["CreationDate"] == now.isoformat() + "Z" # And deletion: delete_event = CloudwatchEventFactory( detail=DetailFactory(requestParameters={"bucketName": "testbucket1"}, source="aws.s3", eventName="DeleteBucket", eventTime=now)) data = json.dumps(delete_event, default=serialize) data = KinesisRecordsFactory( records=[KinesisRecordFactory(kinesis=KinesisDataFactory(data=data))]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, None) assert CurrentS3Model.count() == 0
def test_collector(historical_role, mock_lambda_environment, vpcs, current_vpc_table): from historical.vpc.models import CurrentVPCModel from historical.vpc.collector import handler event = CloudwatchEventFactory(detail=DetailFactory( requestParameters={'vpcId': vpcs['VpcId']}, eventName='CreateVpc'), ) data = json.dumps(event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, None) assert CurrentVPCModel.count() == 1 event = CloudwatchEventFactory(detail=DetailFactory( requestParameters={'vpcId': vpcs['VpcId']}, eventName='DeleteVpc'), ) data = json.dumps(event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, None) assert CurrentVPCModel.count() == 0
def test_collector(historical_role, buckets, mock_lambda_environment, swag_accounts, current_s3_table): """Test the Collector.""" from historical.s3.models import CurrentS3Model from historical.s3.collector import handler now = datetime.utcnow().replace(tzinfo=None, microsecond=0) create_event = CloudwatchEventFactory( detail=DetailFactory(requestParameters={"bucketName": "testbucket1"}, eventSource="aws.s3", eventName="CreateBucket", eventTime=now)) data = json.dumps(create_event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, mock_lambda_environment) result = list(CurrentS3Model.query("arn:aws:s3:::testbucket1")) assert len(result) == 1 assert result[0].Tags.attribute_values["theBucketName"] == "testbucket1" assert result[0].eventSource == "aws.s3" # Polling (make sure the date is included): polling_event = CloudwatchEventFactory( detail=DetailFactory(requestParameters={ "bucketName": "testbucket1", "creationDate": now }, eventSource="historical.s3.poller", eventName="PollS3", eventTime=now)) data = json.dumps(polling_event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, mock_lambda_environment) assert CurrentS3Model.count() == 1 # Load the config and verify the polling timestamp is in there: result = list(CurrentS3Model.query("arn:aws:s3:::testbucket1")) assert result[0].configuration["CreationDate"] == now.isoformat() + "Z" assert result[0].eventSource == "historical.s3.poller" # And deletion: delete_event = CloudwatchEventFactory( detail=DetailFactory(requestParameters={"bucketName": "testbucket1"}, eventSource="aws.s3", eventName="DeleteBucket", eventTime=now)) data = json.dumps(delete_event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, mock_lambda_environment) assert CurrentS3Model.count() == 0
def test_collector_on_deleted_bucket(historical_role, buckets, mock_lambda_environment, swag_accounts, current_s3_table): from historical.s3.collector import handler # If an event arrives on a bucket that is deleted, then it should skip # and wait until the Deletion event arrives. create_event = CloudwatchEventFactory( detail=DetailFactory( requestParameters={ "bucketName": "not-a-bucket" }, source="aws.s3", eventName="PutBucketPolicy", ) ) create_event_data = json.dumps(create_event, default=serialize) data = KinesisRecordsFactory( records=[ KinesisRecordFactory( kinesis=KinesisDataFactory(data=create_event_data)) ] ) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, None) assert CurrentS3Model.count() == 0
def test_deserialize_current_record_to_current_model(historical_role, current_s3_table, buckets): """Tests that a current table event can be deserialized back into proper Current record object.""" from historical.common.dynamodb import deserialize_current_record_to_current_model from historical.s3.models import CurrentS3Model # Create the event to fetch the Current data from: bucket = S3_BUCKET.copy() bucket['eventTime'] = datetime( year=2017, month=5, day=12, hour=10, minute=30, second=0).isoformat() + 'Z' ddb_record = json.loads( json.dumps(DynamoDBRecordFactory(dynamodb=DynamoDBDataFactory( NewImage=bucket, Keys={'arn': bucket['arn']}), eventName='INSERT'), default=serialize)) result = deserialize_current_record_to_current_model( ddb_record, CurrentS3Model) assert result.BucketName == "testbucket1" assert isinstance(result, CurrentS3Model) # And for event_too_big: # Create the bucket in the current table: now = datetime.utcnow().replace(tzinfo=None, microsecond=0) create_event = json.loads( json.dumps(CloudwatchEventFactory(detail=DetailFactory( requestParameters={"bucketName": "testbucket1"}, eventSource="aws.s3", eventName="CreateBucket", eventTime=now)), default=serialize)) process_update_records([create_event]) del bucket['configuration'] ddb_record = json.loads( json.dumps(DynamoDBRecordFactory(dynamodb=DynamoDBDataFactory( NewImage=bucket, Keys={'arn': bucket['arn']}), eventName='INSERT'), default=serialize)) ddb_record[EVENT_TOO_BIG_FLAG] = True result = deserialize_current_record_to_current_model( ddb_record, CurrentS3Model) assert result.BucketName == "testbucket1" assert isinstance(result, CurrentS3Model) # And if the object isn't in the current table: ddb_record = json.loads( json.dumps(DynamoDBRecordFactory(dynamodb=DynamoDBDataFactory( NewImage=bucket, Keys={'arn': 'arn:aws:s3:::notarealbucket'}), eventName='INSERT'), default=serialize)) ddb_record[EVENT_TOO_BIG_FLAG] = True result = deserialize_current_record_to_current_model( ddb_record, CurrentS3Model) assert not result
def test_filter_request_parameters(): """Tests that specific elements can be pulled out of the Request Parameters in the CloudWatch Event.""" from historical.common.cloudwatch import filter_request_parameters event = CloudwatchEventFactory( detail=DetailFactory( requestParameters={'GroupId': 'sg-4e386e31'} ) ) data = json.loads(json.dumps(event, default=serialize)) assert filter_request_parameters('GroupId', data) == 'sg-4e386e31'
def test_snsproxy_dynamodb_differ(historical_role, current_s3_table, durable_s3_table, mock_lambda_environment, buckets): """ This mostly checks that the differ is able to properly load the reduced dataset from the SNSProxy. """ # Create the item in the current table: from historical.s3.collector import handler as current_handler from historical.s3.differ import handler as diff_handler from historical.s3.models import CurrentS3Model, DurableS3Model from historical.common.sns import shrink_sns_blob # Mock out the loggers: import historical.common.dynamodb old_logger = historical.common.dynamodb.log mocked_logger = MagicMock() historical.common.dynamodb.log = mocked_logger now = datetime.utcnow().replace(tzinfo=None, microsecond=0) create_event = CloudwatchEventFactory( detail=DetailFactory(requestParameters={"bucketName": "testbucket1"}, eventSource="aws.s3", eventName="CreateBucket", eventTime=now)) data = json.dumps(create_event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) current_handler(data, mock_lambda_environment) result = list(CurrentS3Model.query("arn:aws:s3:::testbucket1")) assert len(result) == 1 # Mock out the DDB Stream for this creation and for an item that is NOT in the current table:: ttl = int(time.time() + TTL_EXPIRY) new_bucket = S3_BUCKET.copy() new_bucket['eventTime'] = datetime( year=2017, month=5, day=12, hour=10, minute=30, second=0).isoformat() + 'Z' new_bucket['ttl'] = ttl ddb_existing_item = DynamoDBRecordFactory(dynamodb=DynamoDBDataFactory( NewImage=new_bucket, Keys={'arn': new_bucket['arn']}, OldImage=new_bucket), eventName='INSERT') missing_bucket = S3_BUCKET.copy() missing_bucket['eventTime'] = datetime( year=2017, month=5, day=12, hour=10, minute=30, second=0).isoformat() + 'Z' missing_bucket['ttl'] = ttl missing_bucket['BucketName'] = 'notinthecurrenttable' missing_bucket['arn'] = 'arn:aws:s3:::notinthecurrenttable' missing_bucket['configuration']['Name'] = 'notinthecurrenttable' ddb_missing_item = DynamoDBRecordFactory(dynamodb=DynamoDBDataFactory( NewImage=missing_bucket, Keys={'arn': 'arn:aws:s3:::notinthecurrenttable'}, OldImage=new_bucket), eventName='INSERT') # Get the shrunken blob: shrunken_existing = json.dumps( shrink_sns_blob( json.loads(json.dumps(ddb_existing_item, default=serialize)))) shrunken_missing = json.dumps( shrink_sns_blob( json.loads(json.dumps(ddb_missing_item, default=serialize)))) records = RecordsFactory(records=[ SQSDataFactory(body=json.dumps( SnsDataFactory(Message=shrunken_existing), default=serialize)), SQSDataFactory(body=json.dumps( SnsDataFactory(Message=shrunken_missing), default=serialize)) ]) records_event = json.loads(json.dumps(records, default=serialize)) # Run the differ: diff_handler(records_event, mock_lambda_environment) # Verify that the existing bucket in the Current table is in the Durable table with the correct configuration: result = list(DurableS3Model.query("arn:aws:s3:::testbucket1")) assert len(result) == 1 assert result[0].configuration.attribute_values['Name'] == 'testbucket1' # Verify that the missing bucket is ignored -- as it will be processed presumably later: result = list(DurableS3Model.query("arn:aws:s3:::notinthecurrenttable")) assert not result # Verify that the proper log statements were reached: assert mocked_logger.debug.called assert mocked_logger.error.called debug_calls = [ '[-->] Item with ARN: arn:aws:s3:::notinthecurrenttable was too big for SNS ' '-- fetching it from the Current table...', '[+] Saving new revision to durable table.', '[-->] Item with ARN: arn:aws:s3:::testbucket1 was too big for SNS -- fetching it from the Current table...' ] for dc in debug_calls: mocked_logger.debug.assert_any_call(dc) mocked_logger.error.assert_called_once_with( '[?] Received item too big for SNS, and was not able to ' 'find the original item with ARN: arn:aws:s3:::notinthecurrenttable') # Unmock the logger: historical.common.dynamodb.log = old_logger
def test_filter_request_parameters(): from historical.common.cloudwatch import filter_request_parameters event = CloudwatchEventFactory(detail=DetailFactory( requestParameters={'GroupId': 'sg-4e386e31'})) data = json.loads(json.dumps(event, default=serialize)) assert filter_request_parameters('GroupId', data) == 'sg-4e386e31'
def test_collector(historical_role, mock_lambda_environment, historical_sqs, security_groups, current_security_group_table): """Tests the Collector.""" # This should NOT be called at first: def mock_describe_security_groups(**kwargs): assert False patch_sgs = patch('historical.security_group.collector.describe_security_groups', mock_describe_security_groups) patch_sgs.start() from historical.security_group.models import CurrentSecurityGroupModel from historical.security_group.collector import handler from cloudaux.aws.ec2 import describe_security_groups sg_details = describe_security_groups( account_number='012345678910', assume_role='Historical', region='us-east-1', GroupIds=[security_groups['GroupId']])['SecurityGroups'][0] event = CloudwatchEventFactory( detail=DetailFactory( requestParameters={'groupId': security_groups['GroupId']}, eventName='PollSecurityGroups', collected=sg_details)) data = json.dumps(event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, mock_lambda_environment) patch_sgs.stop() group = list(CurrentSecurityGroupModel.scan()) assert len(group) == 1 # Validate that Tags are correct: assert len(group[0].Tags.attribute_values) == 2 assert group[0].Tags.attribute_values['Some'] == 'Value' assert group[0].Tags.attribute_values['Empty'] == '<empty>' group[0].delete() # Standard SG events: event = CloudwatchEventFactory( detail=DetailFactory( requestParameters={'groupId': security_groups['GroupId']}, eventName='CreateSecurityGroup' ), ) data = json.dumps(event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, mock_lambda_environment) group = list(CurrentSecurityGroupModel.scan()) assert len(group) == 1 # Validate that Tags are correct: assert len(group[0].Tags.attribute_values) == 2 assert group[0].Tags.attribute_values['Some'] == 'Value' assert group[0].Tags.attribute_values['Empty'] == '<empty>' event = CloudwatchEventFactory( detail=DetailFactory( requestParameters={'groupId': security_groups['GroupId']}, eventName='DeleteSecurityGroup' ), ) data = json.dumps(event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, mock_lambda_environment) assert CurrentSecurityGroupModel.count() == 0 # Try to get it again -- this time, add the SG ID to the responseElements: event = CloudwatchEventFactory( detail=DetailFactory( responseElements={'groupId': security_groups['GroupId']}, eventName='CreateSecurityGroup' ), ) data = json.dumps(event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, mock_lambda_environment) assert CurrentSecurityGroupModel.count() == 1 # Create a security group in an off-region. Make sure that the ARN of the Security Group is correct and NOT # set to the CURRENT_REGION: client = boto3.client('ec2', region_name='eu-west-2') sg_id = client.create_security_group(GroupName='London', Description='London', VpcId='vpc-test')['GroupId'] sg_details = describe_security_groups( account_number='123456789012', assume_role='Historical', region='eu-west-2', GroupIds=[sg_id])['SecurityGroups'][0] event = CloudwatchEventFactory( detail=DetailFactory( requestParameters={'groupId': sg_id}, eventName='PollSecurityGroups', awsRegion='eu-west-2', collected=sg_details)) data = json.dumps(event, default=serialize) data = RecordsFactory(records=[SQSDataFactory(body=data)]) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, mock_lambda_environment) group = list(CurrentSecurityGroupModel.query(f'arn:aws:ec2:eu-west-2:123456789012:security-group/{sg_id}')) assert len(group) == 1
) ] ) data = json.loads(json.dumps(data, default=serialize)) handler(data, None) assert Durable{{cookiecutter.technology_slug | titlecase}}Model.count() == 5 def test_collector(historical_role, mock_lambda_environment, {{cookiecutter.technology_slug}}s): from .models import Current{{cookiecutter.technology_slug | titlecase}}Model from .collector import handler # TODO modify event event = CloudwatchEventFactory( detail=DetailFactory( requestParameters={}, # e.g. {'vpcId': vpcs['VpcId']}, eventName='', # e.g. 'CreateVpc' ), ) data = json.dumps(event, default=serialize) data = RecordsFactory( records=[ KinesisRecordFactory( kinesis=KinesisDataFactory(data=data)) ] ) data = json.dumps(data, default=serialize) data = json.loads(data) handler(data, None) assert Current{{cookiecutter.technology_slug | titlecase}}Model.count() == 1