def test_sqs_config_translate(test): # we're using a cwe event as a config, so have to mangle to # config's inane format (json strings in json) event = event_data('sqs-discover.json') p = test.load_policy({ 'name': 'sqs-check', 'resource': 'aws.sqs', 'mode': { 'type': 'config-rule' } }) config = p.resource_manager.get_source('config') resource = config.load_resource(event['detail']['configurationItem']) Arn.parse(resource['QueueArn']).resource == 'config-changes' assert resource == { 'CreatedTimestamp': '1602023249', 'DelaySeconds': '0', 'LastModifiedTimestamp': '1602023249', 'MaximumMessageSize': '262144', 'MessageRetentionPeriod': '345600', 'Policy': '{"Version":"2012-10-17","Statement":[{"Sid":"","Effect":"Allow","Principal":{"Service":"events.amazonaws.com"},"Action":"sqs:SendMessage","Resource":"arn:aws:sqs:us-east-1:644160558196:config-changes"}]}', # noqa 'QueueArn': 'arn:aws:sqs:us-east-1:644160558196:config-changes', 'QueueUrl': 'https://sqs.us-east-1.amazonaws.com/644160558196/config-changes', 'ReceiveMessageWaitTimeSeconds': '0', 'VisibilityTimeout': '30', }
def process(self, resources, event=None): filters = [] for f in self.data.get('eval_filters', ()): vf = ValueFilter(f) vf.annotate = False filters.append(vf) resource_model = self.manager.get_model() resource_map = self.get_resource_map(filters, resource_model, resources) # Avoid static/import time dep on boto in filters package from c7n.resources.aws import Arn results = [] for arn, r in zip(self.manager.get_arns(resources), resources): # many aws provided rules are inconsistent in their # treatment of resource ids, some use arns, some use names # as identifiers for the same resource type. security # hub in particular is bad at consistency. rid = None if arn in resource_map: rid = arn elif r[resource_model.id] in resource_map: rid = r[resource_model.id] if arn == r[resource_model.id] and not rid: rid = Arn.parse(arn).resource if rid not in resource_map: rid = None if rid is None: continue r[self.annotation_key] = resource_map[rid] results.append(r) return results
def get_resource_arns(self, event): event_type = event['detail-type'] arn_resolver = getattr(self, self.handlers[event_type]) arns = arn_resolver(event) # Lazy import to avoid aws sdk runtime dep in core from c7n.resources.aws import Arn return {Arn.parse(r) for r in arns}
def resolve_resources(self, event): # For centralized setups in a hub aggregator account self.assume_member(event) event_type = event['detail-type'] arn_resolver = getattr(self, self.handlers[event_type]) arns = arn_resolver(event) # Lazy import to avoid aws sdk runtime dep in core from c7n.resources.aws import Arn resource_map = {Arn.parse(r) for r in arns} # sanity check on finding resources matching policy resource # type's service. if self.policy.resource_manager.type != 'account': log.info("mode:security-hub resolve resources %s", list(resource_map)) if not resource_map: return [] resource_arns = [ r for r in resource_map if r.service == self.policy.resource_manager.resource_type.service ] resources = self.policy.resource_manager.get_resources( [r.resource for r in resource_arns]) else: resources = self.policy.resource_manager.get_resources([]) resources[0]['resource-arns'] = resource_arns return resources
def get_resource_sets(self, event): # return a mapping of (account_id, region): [resource_arns] # per the finding in the event. # Group resources by account_id, region for role assumes resource_sets = {} # Loop over findings and set resource set accordingly # Lazy import to avoid aws sdk runtime dep in core from c7n.resources.aws import Arn for finding in event['detail']['findings']: resource_sets.setdefault( (finding['AwsAccountId'], finding['Resources'][0]['Region']), []).append(Arn.parse(finding['Resources'][0]['Id'])) # Warn if not configured for member-role and have multiple accounts resources. if (not self.policy.data['mode'].get('member-role') and {self.policy.options.account_id} != { account_id for (account_id, region), rarns in resource_sets.items() }): msg = ('hub-mode not configured for multi-account member-role ' 'but multiple resource accounts found') self.policy.log.warning(msg) raise PolicyExecutionError(msg) return resource_sets
def process(self, resources): client = local_session(self.manager.session_factory).client('s3control') for r in resources: arn = Arn.parse(r['AccessPointArn']) try: client.delete_access_point(AccountId=arn.account_id, Name=r['Name']) except client.NotFoundException: continue
def augment(self, resources): client = local_session(self.manager.session_factory).client('s3control') results = [] for r in resources: arn = Arn.parse(r['AccessPointArn']) ap = client.get_access_point(AccountId=arn.account_id, Name=r['Name']) ap.pop('ResponseMetadata', None) results.append(ap) return results
def process(self, resources, event=None): client = local_session(self.manager.session_factory).client('s3control') for r in resources: if self.policy_attribute in r: continue arn = Arn.parse(r['AccessPointArn']) r[self.policy_attribute] = client.get_access_point_policy( AccountId=arn.account_id, Name=r['Name'] ).get('Policy') return super().process(resources, event)
def get_resources(self, ids, cache=True): ids_normalized = [] for i in ids: if not i.startswith('https://'): ids_normalized.append(i) continue ids_normalized.append(i.rsplit('/', 1)[-1]) resources = super(SQS, self).get_resources(ids_normalized, cache) return [ r for r in resources if Arn.parse(r['QueueArn']).resource in ids_normalized ]
def test_resolve_import_finding(self): factory = self.replay_flight_data('test_security_hub_mode_resolve') policy = self.load_policy({ 'name': 'trail-fixer', 'resource': 'aws.iam-user', 'mode': { 'type': 'hub-finding', 'role': 'foo'}}, session_factory=factory) event = event_data("event-securityhub-iamkey-finding-action.json") hub = policy.get_execution_mode() resources = hub.resolve_import_finding(event) self.assertEqual( sorted(resources), sorted(['arn:aws:iam::644160558196:user/kapil'])) # Lazy import to avoid aws sdk runtime dep in core from c7n.resources.aws import Arn resources = hub.resolve_resources({Arn.parse(r) for r in resources}) self.assertEqual(len(resources), 1) self.assertEqual(resources[0]['UserName'], 'kapil')
def get_dimensions(self, resource): return [{ 'Name': self.model.dimension, 'Value': Arn.parse(resource['LoadBalancerArn']).resource }]