def test_cwe_trail(self): session_factory = self.replay_flight_data("test_cwe_trail", zdata=True) p = Policy( { "resource": "s3", "name": "s3-bucket-policy", "mode": {"type": "cloudtrail", "events": ["CreateBucket"]}, "filters": [ { "type": "missing-policy-statement", "statement_ids": ["RequireEncryptedPutObject"], } ], "actions": ["no-op"], }, Config.empty(), ) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) self.addCleanup(mgr.remove, pl) result = mgr.publish(pl, "Dev", role=ROLE) events = pl.get_events(session_factory) self.assertEqual(len(events), 1) event = events.pop() self.assertEqual( json.loads(event.render_event_pattern()), { u"detail": { u"eventName": [u"CreateBucket"], u"eventSource": [u"s3.amazonaws.com"], }, u"detail-type": ["AWS API Call via CloudTrail"], }, ) self.assert_items( result, { "Description": "cloud-custodian lambda policy", "FunctionName": "custodian-s3-bucket-policy", "Handler": "custodian_policy.run", "MemorySize": 512, "Runtime": "python2.7", "Timeout": 60, }, )
def test_config_defaults(self): p = PolicyLambda(Bag({'name': 'hello', 'data': {'mode': {}}})) self.maxDiff = None self.assertEqual( p.get_config(), {'DeadLetterConfig': {}, 'Description': 'cloud-custodian lambda policy', 'Environment': {'Variables': {}}, 'FunctionName': 'custodian-hello', 'Handler': 'custodian_policy.run', 'KMSKeyArn': '', 'MemorySize': 512, 'Role': '', 'Runtime': 'python2.7', 'Tags': {}, 'Timeout': 60, 'TracingConfig': {'Mode': 'PassThrough'}, 'VpcConfig': {'SecurityGroupIds': [], 'SubnetIds': []}})
def test_config_defaults(self): p = PolicyLambda(Bag({"name": "hello", "data": {"mode": {}}})) self.maxDiff = None self.assertEqual( p.get_config(), { "DeadLetterConfig": {}, "Description": "cloud-custodian lambda policy", "FunctionName": "custodian-hello", "Handler": "custodian_policy.run", "KMSKeyArn": "", "MemorySize": 512, "Role": "", "Runtime": "python3.7", "Tags": {}, "Timeout": 60, "TracingConfig": {"Mode": "PassThrough"}, "VpcConfig": {"SecurityGroupIds": [], "SubnetIds": []}, }, )
def test_phd_mode(self): factory = self.replay_flight_data('test_phd_event_mode') p = self.load_policy( {'name': 'ec2-retire', 'resource': 'ec2', 'mode': { 'categories': ['scheduledChange'], 'events': ['AWS_EC2_PERSISTENT_INSTANCE_RETIREMENT_SCHEDULED'], 'type': 'phd'}}, session_factory=factory) mode = p.get_execution_mode() event = event_data('event-phd-ec2-retire.json') resources = mode.run(event, None) self.assertEqual(len(resources), 1) p_lambda = PolicyLambda(p) events = p_lambda.get_events(factory) self.assertEqual( json.loads(events[0].render_event_pattern()), {'detail': { 'eventTypeCategory': ['scheduledChange'], 'eventTypeCode': ['AWS_EC2_PERSISTENT_INSTANCE_RETIREMENT_SCHEDULED']}, 'source': ['aws.health']} )
def test_cwe_trail(self): session_factory = self.replay_flight_data('test_cwe_trail', zdata=True) p = Policy({ 'resource': 's3', 'name': 's3-bucket-policy', 'mode': { 'type': 'cloudtrail', 'events': ["CreateBucket"], }, 'filters': [ {'type': 'missing-policy-statement', 'statement_ids': ['RequireEncryptedPutObject']}], 'actions': ['no-op'] }, Config.empty()) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) result = mgr.publish(pl, 'Dev', role=self.role) events = pl.get_events(session_factory) self.assertEqual(len(events), 1) event = events.pop() self.assertEqual( json.loads(event.render_event_pattern()), {u'detail': {u'eventName': [u'CreateBucket'], u'eventSource': [u'aws.s3']}, u'detail-type': ['AWS API Call via CloudTrail']}) self.assert_items( result, {'Description': 'cloud-custodian lambda policy', 'FunctionName': 'custodian-s3-bucket-policy', 'Handler': 'custodian_policy.run', 'MemorySize': 512, 'Runtime': 'python2.7', 'Timeout': 60}) mgr.remove(pl)
def update_a_lambda(self, mgr, **config): mode = { "type": "config-rule", "role": "arn:aws:iam::644160558196:role/custodian-mu" } mode.update(config) p = Policy( { "resource": "s3", "name": "hello-world", "actions": ["no-op"], "mode": mode, }, Config.empty(), ) pl = PolicyLambda(p) return mgr.publish(pl)
def test_config_rule_provision(self): session_factory = self.replay_flight_data("test_config_rule") p = Policy( { "resource": "security-group", "name": "sg-modified", "mode": { "type": "config-rule" }, }, Config.empty(), ) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) result = mgr.publish(pl, "Dev", role=ROLE) self.assertEqual(result["FunctionName"], "custodian-sg-modified") self.addCleanup(mgr.remove, pl)
def provision(self): # Avoiding runtime lambda dep, premature optimization? from c7n.mu import PolicyLambda, LambdaManager with self.policy.ctx: self.policy.log.info("Provisioning policy lambda %s", self.policy.name) try: manager = LambdaManager(self.policy.session_factory) except ClientError: # For cli usage by normal users, don't assume the role just use # it for the lambda manager = LambdaManager( lambda assume=False: self.policy.session_factory(assume)) return manager.publish(PolicyLambda(self.policy), 'current', role=self.policy.options.assume_role)
def test_cwe_asg_instance(self): session_factory = self.replay_flight_data("test_cwe_asg", zdata=True) p = self.load_policy( { "resource": "asg", "name": "asg-spin-detector", "mode": { "type": "asg-instance-state", "events": ["launch-failure"] }, }, session_factory=session_factory) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) self.addCleanup(mgr.remove, pl) result = mgr.publish(pl, "Dev", role=ROLE) self.assert_items( result, { "FunctionName": "custodian-asg-spin-detector", "Handler": "custodian_policy.run", "MemorySize": 512, "Runtime": "python2.7", "Timeout": 60, }, ) events = session_factory().client("events") result = events.list_rules(NamePrefix="custodian-asg-spin-detector") self.assert_items( result["Rules"][0], { "State": "ENABLED", "Name": "custodian-asg-spin-detector" }, ) self.assertEqual( json.loads(result["Rules"][0]["EventPattern"]), { "source": ["aws.autoscaling"], "detail-type": ["EC2 Instance Launch Unsuccessful"], }, )
def create_a_lambda(self, flight, **extra): session_factory = self.replay_flight_data(flight, zdata=True) mode = { 'type': 'config-rule', 'role': 'arn:aws:iam::644160558196:role/custodian-mu' } mode.update(extra) p = Policy( { 'resource': 's3', 'name': 'hello-world', 'actions': ['no-op'], 'mode': mode, }, Config.empty()) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) self.addCleanup(mgr.remove, pl) return mgr, mgr.publish(pl)
def test_optional_packages(self): p = Policy( { "resources": "s3", "name": "s3-lambda-extra", "resource": "s3", "mode": { "type": "cloudtrail", "packages": ["boto3", "botocore"], "events": ["CreateBucket"], }, }, Config.empty(), ) pl = PolicyLambda(p) pl.archive.close() self.assertTrue("boto3/utils.py" in pl.archive.get_filenames()) self.assertTrue("botocore/utils.py" in pl.archive.get_filenames())
def test_mu_metrics(self): session_factory = self.replay_flight_data('test_mu_metrics') p = Policy({ 'resources': 's3', 'name': 's3-bucket-policy', 'resource': 's3', 'mode': { 'type': 'cloudtrail', 'events': ['CreateBucket'], }, 'actions': ['no-op']}, Config.empty()) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) end = datetime.utcnow() start = end - timedelta(1) results = mgr.metrics([pl], start, end, 3600) self.assertEqual( results, [{'Durations': [], 'Errors': [], 'Throttles': [], 'Invocations': []}])
def test_mu_metrics(self): session_factory = self.replay_flight_data("test_mu_metrics") p = self.load_policy( { "name": "s3-bucket-policy", "resource": "s3", "mode": {"type": "cloudtrail", "events": ["CreateBucket"]}, "actions": ["no-op"], }, session_factory=session_factory) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) end = datetime.utcnow() start = end - timedelta(1) results = mgr.metrics([pl], start, end, 3600) self.assertEqual( results, [{"Durations": [], "Errors": [], "Throttles": [], "Invocations": []}], )
def test_cwe_instance(self): session_factory = self.replay_flight_data('test_cwe_instance', zdata=True) p = Policy( { 'resource': 's3', 'name': 'ec2-encrypted-vol', 'mode': { 'type': 'ec2-instance-state', 'events': ['pending'] } }, Config.empty()) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) result = mgr.publish(pl, 'Dev', role=self.role) self.assert_items( result, { 'Description': 'cloud-maid lambda policy', 'FunctionName': 'maid-ec2-encrypted-vol', 'Handler': 'maid_policy.run', 'MemorySize': 512, 'Runtime': 'python2.7', 'Timeout': 60 }) events = session_factory().client('events') result = events.list_rules(NamePrefix="maid-ec2-encrypted-vol") self.assert_items(result['Rules'][0], { "State": "ENABLED", "Name": "maid-ec2-encrypted-vol" }) self.assertEqual( json.loads(result['Rules'][0]['EventPattern']), { "source": ["aws.ec2"], "detail": { "state": ["pending"] }, "detail-type": ["EC2 Instance State-change Notification"] }) mgr.remove(pl)
def test_cwe_instance(self): session_factory = self.replay_flight_data("test_cwe_instance", zdata=True) p = Policy( { "resource": "s3", "name": "ec2-encrypted-vol", "mode": {"type": "ec2-instance-state", "events": ["pending"]}, }, Config.empty(), ) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) self.addCleanup(mgr.remove, pl) result = mgr.publish(pl, "Dev", role=ROLE) self.assert_items( result, { "Description": "cloud-custodian lambda policy", "FunctionName": "custodian-ec2-encrypted-vol", "Handler": "custodian_policy.run", "MemorySize": 512, "Runtime": "python2.7", "Timeout": 60, }, ) events = session_factory().client("events") result = events.list_rules(NamePrefix="custodian-ec2-encrypted-vol") self.assert_items( result["Rules"][0], {"State": "ENABLED", "Name": "custodian-ec2-encrypted-vol"}, ) self.assertEqual( json.loads(result["Rules"][0]["EventPattern"]), { "source": ["aws.ec2"], "detail": {"state": ["pending"]}, "detail-type": ["EC2 Instance State-change Notification"], }, )
def test_cwe_schedule(self): session_factory = self.replay_flight_data("test_cwe_schedule", zdata=True) p = Policy( { "resource": "ec2", "name": "periodic-ec2-checker", "mode": { "type": "periodic", "schedule": "rate(1 day)" }, }, Config.empty(), ) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) self.addCleanup(mgr.remove, pl) result = mgr.publish(pl, "Dev", role=ROLE) self.assert_items( result, { "FunctionName": "custodian-periodic-ec2-checker", "Handler": "custodian_policy.run", "MemorySize": 512, "Runtime": "python2.7", "Timeout": 60, }, ) events = session_factory().client("events") result = events.list_rules(NamePrefix="custodian-periodic-ec2-checker") self.assert_items( result["Rules"][0], { "State": "ENABLED", "ScheduleExpression": "rate(1 day)", "Name": "custodian-periodic-ec2-checker", }, )
def create_a_lambda(self, flight, **extra): session_factory = self.replay_flight_data(flight, zdata=True) mode = { "type": "config-rule", "role": "arn:aws:iam::644160558196:role/custodian-mu" } mode.update(extra) p = self.load_policy({ "resource": "s3", "name": "hello-world", "actions": ["no-op"], "mode": mode}, session_factory=session_factory) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) def cleanup(): mgr.remove(pl) if self.recording: time.sleep(60) self.addCleanup(cleanup) return mgr, mgr.publish(pl)
def test_cwe_asg_instance(self): session_factory = self.replay_flight_data('test_cwe_asg', zdata=True) p = Policy( { 'resource': 'asg', 'name': 'asg-spin-detector', 'mode': { 'type': 'asg-instance-state', 'events': ['launch-failure'] } }, Config.empty()) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) result = mgr.publish(pl, 'Dev', role=self.role) self.assert_items( result, { 'FunctionName': 'maid-asg-spin-detector', 'Handler': 'maid_policy.run', 'MemorySize': 512, 'Runtime': 'python2.7', 'Timeout': 60 }) events = session_factory().client('events') result = events.list_rules(NamePrefix="maid-asg-spin-detector") self.assert_items(result['Rules'][0], { "State": "ENABLED", "Name": "maid-asg-spin-detector" }) self.assertEqual( json.loads(result['Rules'][0]['EventPattern']), { "source": ["aws.autoscaling"], "detail-type": ["EC2 Instance Launch Unsuccessful"] }) mgr.remove(pl)
def test_cwe_update_config_and_code(self): # Originally this was testing the no update case.. but # That is tricky to record, any updates to the code end up # causing issues due to checksum mismatches which imply updating # the function code / which invalidate the recorded data and # the focus of the test. session_factory = self.replay_flight_data("test_cwe_update", zdata=True) p = self.load_policy({ "resource": "s3", "name": "s3-bucket-policy", "mode": { "type": "cloudtrail", "events": ["CreateBucket"], 'runtime': 'python2.7' }, "filters": [ { "type": "missing-policy-statement", "statement_ids": ["RequireEncryptedPutObject"] }, ], "actions": ["no-op"], }) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) result = mgr.publish(pl, "Dev", role=ROLE) self.addCleanup(mgr.remove, pl) p = self.load_policy( { "resource": "s3", "name": "s3-bucket-policy", "mode": { "type": "cloudtrail", "memory": 256, 'runtime': 'python2.7', "events": [ "CreateBucket", { "event": "PutBucketPolicy", "ids": "requestParameters.bucketName", "source": "s3.amazonaws.com", }, ], }, "filters": [{ "type": "missing-policy-statement", "statement_ids": ["RequireEncryptedPutObject"], }], "actions": ["no-op"], }, ) output = self.capture_logging("custodian.serverless", level=logging.DEBUG) result2 = mgr.publish(PolicyLambda(p), "Dev", role=ROLE) lines = output.getvalue().strip().split("\n") self.assertTrue( "Updating function custodian-s3-bucket-policy code" in lines) self.assertTrue( "Updating function: custodian-s3-bucket-policy config MemorySize" in lines) self.assertEqual(result["FunctionName"], result2["FunctionName"]) # drive by coverage functions = [ i for i in mgr.list_functions() if i["FunctionName"] == "custodian-s3-bucket-policy" ] self.assertTrue(len(functions), 1) start = 0 end = time.time() * 1000 self.assertEqual(list(mgr.logs(pl, start, end)), [])
def test_cwe_update_config_and_code(self): # Originally this was testing the no update case.. but # That is tricky to record, any updates to the code end up # causing issues due to checksum mismatches which imply updating # the function code / which invalidate the recorded data and # the focus of the test. session_factory = self.replay_flight_data('test_cwe_update', zdata=True) p = Policy( { 'resource': 's3', 'name': 's3-bucket-policy', 'mode': { 'type': 'cloudtrail', 'events': ["CreateBucket"], }, 'filters': [{ 'type': 'missing-policy-statement', 'statement_ids': ['RequireEncryptedPutObject'] }], 'actions': ['no-op'] }, Config.empty()) pl = PolicyLambda(p) mgr = LambdaManager(session_factory) result = mgr.publish(pl, 'Dev', role=ROLE) self.addCleanup(mgr.remove, pl) p = Policy( { 'resource': 's3', 'name': 's3-bucket-policy', 'mode': { 'type': 'cloudtrail', 'memory': 256, 'events': [ "CreateBucket", { 'event': 'PutBucketPolicy', 'ids': 'requestParameters.bucketName', 'source': 's3.amazonaws.com' } ] }, 'filters': [{ 'type': 'missing-policy-statement', 'statement_ids': ['RequireEncryptedPutObject'] }], 'actions': ['no-op'] }, Config.empty()) output = self.capture_logging('custodian.lambda', level=logging.DEBUG) result2 = mgr.publish(PolicyLambda(p), 'Dev', role=ROLE) lines = output.getvalue().strip().split('\n') self.assertTrue( 'Updating function custodian-s3-bucket-policy code' in lines) self.assertTrue( 'Updating function: custodian-s3-bucket-policy config' in lines) self.assertEqual(result['FunctionName'], result2['FunctionName']) # drive by coverage functions = [ i for i in mgr.list_functions() if i['FunctionName'] == 'custodian-s3-bucket-policy' ] self.assertTrue(len(functions), 1) start = 0 end = time.time() * 1000 self.assertEqual(list(mgr.logs(pl, start, end)), [])