for finding in self.manager.retry( client.list_findings, analyzerArn=analyzer_arn, filter=filters).get('findings', ()): r = resource_set[finding['resource']] r.setdefault(self.analysis_annotation, []).append(finding) def get_analyzer(self, client): if self.data.get('analyzer'): return self.data['analyzer'] analyzers = client.list_analyzers(type='ACCOUNT').get('analyzers', ()) found = False for a in analyzers: if a['status'] != 'ACTIVE': continue found = a if not found: raise PolicyExecutionError( "policy:%s no access analyzer found in account or org analyzer specified" % ( self.manager.policy.name )) return found['arn'] @classmethod def register_resources(klass, registry, resource_class): if resource_class.resource_type.cfn_type not in klass.supported_types: return resource_class.filter_registry.register('iam-analyzer', klass) resources.subscribe(AccessAnalyzer.register_resources)
now, 'Value': value, # TODO: support an operation of 'stats' to include this # structure instead of a single Value # Value and StatisticValues are mutually exclusive. # 'StatisticValues': { # 'SampleCount': 1, # 'Sum': 123.0, # 'Minimum': 123.0, # 'Maximum': 123.0 # }, 'Unit': units, }, ] client = utils.local_session( self.manager.session_factory).client('cloudwatch') client.put_metric_data(Namespace=ns, MetricData=metrics_data) return resources @classmethod def register_resources(cls, registry, resource_class): if 'put-metric' not in resource_class.action_registry: resource_class.action_registry.register('put-metric', PutMetric) resources.subscribe(PutMetric.register_resources)
def invoke_batch(self, client, params, pinput, resource_set): for batch_rset in chunks(resource_set, self.data.get('batch-size', 250)): pinput['resources'] = [rarn for rarn, _ in batch_rset] params['input'] = dumps(pinput) exec_arn = self.manager.retry( client.start_execution, **params).get('executionArn') for _, r in resource_set: r['c7n:execution-arn'] = exec_arn @classmethod def register_resources(cls, registry, resource_class): if 'invoke-sfn' not in resource_class.action_registry: resource_class.action_registry.register('invoke-sfn', cls) resources.subscribe(InvokeStepFunction.register_resources) @StepFunction.action_registry.register('tag') class TagStepFunction(Tag): """Action to create tag(s) on a step function :example: .. code-block:: yaml policies: - name: tag-step-function resource: step-machine actions: - type: tag
tag_already_set = True break if not tag_already_set: untagged_resources.append(resource) # if update is set to True, we will overwrite the userName tag even if # the user already set a value else: untagged_resources = resources tag_action = self.manager.action_registry.get('tag') new_tags = { self.data['tag']: user } # if principal_id_key is set (and value), we'll set the principalId tag. principal_id_key = self.data.get('principal_id_tag', None) if principal_id_key and principal_id_value: new_tags[principal_id_key] = principal_id_value for key, value in six.iteritems(new_tags): tag_action({'key': key, 'value': value}, self.manager).process(untagged_resources) return new_tags def register_action_tag_user(registry, _): for resource in registry.keys(): klass = registry.get(resource) if klass.action_registry.get('tag') and not klass.action_registry.get('auto-tag-user'): klass.action_registry.register('auto-tag-user', AutoTagUser) resources.subscribe(resources.EVENT_FINAL, register_action_tag_user)
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 @classmethod def register_resources(klass, registry, resource_class): """model resource subscriber on resource registration. Watch for new resource types being registered if they are supported by aws config, automatically, register the config-compliance filter. """ if (resource_class.resource_type.cfn_type is None and resource_class.resource_type.config_type is None): return resource_class.filter_registry.register('config-compliance', klass) resources.subscribe(ConfigCompliance.register_resources)
params['Payload'] = utils.dumps(payload) result = client.invoke(**params) result['Payload'] = result['Payload'].read() if isinstance(result['Payload'], bytes): result['Payload'] = result['Payload'].decode('utf-8') results.append(result) return results def register_action_invoke_lambda(registry, _): for resource in registry.keys(): klass = registry.get(resource) klass.action_registry.register('invoke-lambda', LambdaInvoke) resources.subscribe(resources.EVENT_FINAL, register_action_invoke_lambda) class BaseNotify(EventAction): batch_size = 250 def expand_variables(self, message): """expand any variables in the action to_from/cc_from fields. """ p = copy.deepcopy(self.data) if 'to_from' in self.data: to_from = self.data['to_from'].copy() to_from['url'] = to_from['url'].format(**message) if 'expr' in to_from: to_from['expr'] = to_from['expr'].format(**message)
elif isinstance(v, (list, dict)): v = dumps(v) elif isinstance(v, (int, float, bool)): v = str(v) else: continue details[k] = v details['c7n:resource-type'] = self.manager.type other = { 'Type': 'Other', 'Id': self.manager.get_arns([r])[0], 'Region': self.manager.config.region, 'Details': {'Other': filter_empty(details)} } tags = {t['Key']: t['Value'] for t in r.get('Tags', [])} if tags: other['Tags'] = tags return other @classmethod def register_resource(klass, registry, event): for rtype, resource_manager in registry.items(): if 'post-finding' in resource_manager.action_registry: continue resource_manager.action_registry.register('post-finding', klass) aws_resources.subscribe( aws_resources.EVENT_FINAL, OtherResourcePostFinding.register_resource)
alias = utils.get_account_alias_from_sts( utils.local_session(self.manager.session_factory)) payload = { 'version': VERSION, 'event': event, 'account_id': self.manager.config.account_id, 'account': alias, 'region': self.manager.config.region, 'action': self.data, 'policy': self.manager.data} results = [] for resource_set in utils.chunks(resources, self.data.get('batch_size', 250)): payload['resources'] = resource_set params['Payload'] = utils.dumps(payload) result = client.invoke(**params) result['Payload'] = result['Payload'].read() if isinstance(result['Payload'], bytes): result['Payload'] = result['Payload'].decode('utf-8') results.append(result) return results @classmethod def register_resources(klass, registry, resource_class): if 'invoke-lambda' not in resource_class.action_registry: resource_class.action_registry.register('invoke-lambda', LambdaInvoke) resources.subscribe(LambdaInvoke.register_resources)
params['Payload'] = utils.dumps(payload) result = client.invoke(**params) result['Payload'] = result['Payload'].read() if isinstance(result['Payload'], bytes): result['Payload'] = result['Payload'].decode('utf-8') results.append(result) return results def register_action_invoke_lambda(registry, _): for resource in registry.keys(): klass = registry.get(resource) klass.action_registry.register('invoke-lambda', LambdaInvoke) resources.subscribe(resources.EVENT_FINAL, register_action_invoke_lambda) class BaseNotify(EventAction): batch_size = 250 def expand_variables(self, message): """expand any variables in the action to_from/cc_from fields. """ p = copy.deepcopy(self.data) if 'to_from' in self.data: to_from = self.data['to_from'].copy() to_from['url'] = to_from['url'].format(**message) if 'expr' in to_from: to_from['expr'] = to_from['expr'].format(**message)
selector_value={'type': 'string'}) def diff(self, source, target): source, target = (self.sanitize_revision(source), self.sanitize_revision(target)) patch = jsonpatch.JsonPatch.from_diff(source, target) return list(patch) def sanitize_revision(self, rev): sanitized = dict(rev) for k in [k for k in sanitized if 'c7n' in k]: sanitized.pop(k) return sanitized @classmethod def register_resources(klass, registry, resource_class): """ meta model subscriber on resource registration. We watch for new resource types being registered and if they support aws config, automatically register the jsondiff filter. """ config_type = getattr(resource_class.resource_type, 'config_type', None) if config_type is None: return resource_class.filter_registry.register('json-diff', klass) if HAVE_JSONPATH: resources.subscribe(resources.EVENT_REGISTER, JsonDiff.register_resources)
resource_model = self.manager.get_model() resource_map = self.get_resource_map(filters, resource_model, resources) results = [] for r in resources: if r[resource_model.id] not in resource_map: continue r[self.annotation_key] = resource_map[r[resource_model.id]] results.append(r) return results @classmethod def register_resources(klass, registry, resource_class): """model resource subscriber on resource registration. Watch for new resource types being registered if they support aws config, automatically, register the config-compliance filter. """ config_type = getattr(resource_class.resource_type, 'config_type', None) if config_type is None: return resource_class.filter_registry.register('config-compliance', klass) resources.subscribe(resources.EVENT_REGISTER, ConfigCompliance.register_resources)
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) results = [] for r in resources: if r[resource_model.id] not in resource_map: continue r[self.annotation_key] = resource_map[r[resource_model.id]] results.append(r) return results @classmethod def register_resources(klass, registry, resource_class): """model resource subscriber on resource registration. Watch for new resource types being registered if they support aws config, automatically, register the config-compliance filter. """ config_type = getattr(resource_class.resource_type, 'config_type', None) if config_type is None: return resource_class.filter_registry.register('config-compliance', klass) resources.subscribe(resources.EVENT_REGISTER, ConfigCompliance.register_resources)
selector={'enum': ['previous', 'date', 'locked']}, # For date selectors allow value specification selector_value={'type': 'string'}) def diff(self, source, target): source, target = ( self.sanitize_revision(source), self.sanitize_revision(target)) patch = jsonpatch.JsonPatch.from_diff(source, target) return list(patch) def sanitize_revision(self, rev): sanitized = dict(rev) for k in [k for k in sanitized if 'c7n' in k]: sanitized.pop(k) return sanitized @classmethod def register_resources(klass, registry, resource_class): """ meta model subscriber on resource registration. We watch for new resource types being registered and if they support aws config, automatically register the jsondiff filter. """ if resource_class.resource_type.config_type is None: return resource_class.filter_registry.register('json-diff', klass) if HAVE_JSONPATH: resources.subscribe(JsonDiff.register_resources)
if not tag_already_set: untagged_resources.append(resource) # if update is set to True, we will overwrite the userName tag even if # the user already set a value else: untagged_resources = resources tag_action = self.manager.action_registry.get('tag') new_tags = {self.data['tag']: user} # if principal_id_key is set (and value), we'll set the principalId tag. principal_id_key = self.data.get('principal_id_tag', None) if principal_id_key and principal_id_value: new_tags[principal_id_key] = principal_id_value for key, value in new_tags.items(): tag_action({ 'key': key, 'value': value }, self.manager).process(untagged_resources) return new_tags @classmethod def register_resource(cls, registry, resource_class): if 'auto-tag-user' in resource_class.action_registry: return if resource_class.action_registry.get('tag'): resource_class.action_registry.register('auto-tag-user', AutoTagUser) resources.subscribe(AutoTagUser.register_resource)
r_id = manager.resource_type.id return { r[r_id]: {t['Key']: t['Value'] for t in r.get('Tags', [])} for r in manager.get_resources(list(ids)) } @classmethod def register_resources(klass, registry, resource_class): if not resource_class.action_registry.get('tag'): return resource_class.action_registry.register('copy-related-tag', klass) aws_resources.subscribe(CopyRelatedResourceTag.register_resources) def universal_retry(method, ResourceARNList, **kw): """Retry support for resourcegroup tagging apis. The resource group tagging api typically returns a 200 status code with embedded resource specific errors. To enable resource specific retry on throttles, we extract those, perform backoff w/ jitter and continue. Other errors are immediately raised. We do not aggregate unified resource responses across retries, only the last successful response is returned for a subset of the resources if a retry is performed. """ max_attempts = 6
'successfulSet', ()): event_map[d['event']['arn']]['Description'] = d[ 'eventDescription']['latestDescription'] paginator = client.get_paginator('describe_affected_entities') entities.extend( list( itertools.chain(*[ p['entities'] for p in paginator.paginate( filter={'eventArns': event_arns}) ]))) return entities @classmethod def register_resources(klass, registry, resource_class): """ meta model subscriber on resource registration. We watch for PHD event that provides affected entities and register the health-event filter to the resources. """ services = { 'acm-certificate', 'directconnect', 'dms-instance', 'directory', 'ec2', 'dynamodb-table', 'cache-cluster', 'efs', 'app-elb', 'elb', 'emr', 'rds', 'storage-gateway' } if resource_class.type in services: resource_class.filter_registry.register('health-event', klass) resources.subscribe(resources.EVENT_REGISTER, HealthEventFilter.register_resources)
'Timestamp': now, 'Value': value, # TODO: support an operation of 'stats' to include this # structure instead of a single Value # Value and StatisticValues are mutually exclusive. # 'StatisticValues': { # 'SampleCount': 1, # 'Sum': 123.0, # 'Minimum': 123.0, # 'Maximum': 123.0 # }, 'Unit': units, }, ] client = utils.local_session( self.manager.session_factory).client('cloudwatch') client.put_metric_data(Namespace=ns, MetricData=metrics_data) return resources def register_action_put_metric(registry, _): # apply put metric to each resource for resource in registry.keys(): klass = registry.get(resource) klass.action_registry.register('put-metric', PutMetric) resources.subscribe(resources.EVENT_FINAL, register_action_put_metric)
manager = self.manager.get_resource_manager(r_type) r_id = manager.resource_type.id # TODO only fetch resource with the given ids. return { r[r_id]: {t['Key']: t['Value'] for t in r.get('Tags', [])} for r in manager.resources() if r[r_id] in ids } @classmethod def register_resources(klass, registry, resource_class): if not resource_class.action_registry.get('tag'): return resource_class.action_registry.register('copy-related-tag', klass) aws_resources.subscribe( aws_resources.EVENT_REGISTER, CopyRelatedResourceTag.register_resources) def universal_retry(method, ResourceARNList, **kw): """Retry support for resourcegroup tagging apis. The resource group tagging api typically returns a 200 status code with embedded resource specific errors. To enable resource specific retry on throttles, we extract those, perform backoff w/ jitter and continue. Other errors are immediately raised. We do not aggregate unified resource responses across retries, only the last successful response is returned for a subset of the resources if a retry is performed. """ max_attempts = 6
principal_id_key = self.data.get('principal_id_tag', None) if principal_id_key and principal_id_value: new_tags[principal_id_key] = principal_id_value for key, value in six.iteritems(new_tags): tag_action({'key': key, 'value': value}, self.manager).process(untagged_resources) return new_tags def add_auto_tag_user(registry, _): for resource in registry.keys(): klass = registry.get(resource) if klass.action_registry.get('tag') and not klass.action_registry.get('auto-tag-user'): klass.action_registry.register('auto-tag-user', AutoTagUser) resources.subscribe(resources.EVENT_FINAL, add_auto_tag_user) class PutMetric(BaseAction): """Action to put metrics based on an expression into CloudWatch metrics :example: .. code-block:: yaml policies: - name: track-attached-ebs resource: ec2 comment: | Put the count of the number of EBS attached disks to an instance filters:
def process_event(self, client, health_events): entities = [] for event_set in chunks(health_events, 10): event_map = {e['arn']: e for e in event_set} event_arns = list(event_map.keys()) for d in client.describe_event_details( eventArns=event_arns).get('successfulSet', ()): event_map[d['event']['arn']]['Description'] = d[ 'eventDescription']['latestDescription'] paginator = client.get_paginator('describe_affected_entities') entities.extend(list(itertools.chain( *[p['entities'] for p in paginator.paginate( filter={'eventArns': event_arns})]))) return entities @classmethod def register_resources(klass, registry, resource_class): """ meta model subscriber on resource registration. We watch for PHD event that provides affected entities and register the health-event filter to the resources. """ services = {'acm-certificate', 'directconnect', 'dms-instance', 'directory', 'ec2', 'dynamodb-table', 'cache-cluster', 'efs', 'app-elb', 'elb', 'emr', 'rds', 'storage-gateway'} if resource_class.type in services: resource_class.filter_registry.register('health-event', klass) resources.subscribe(HealthEventFilter.register_resources)
params['Qualifier'] = self.data['Qualifier'] if self.data.get('async', True): params['InvocationType'] = 'Event' payload = { 'version': VERSION, 'event': event, 'action': self.data, 'policy': self.manager.data} results = [] for resource_set in utils.chunks(resources, self.data.get('batch_size', 250)): payload['resources'] = resource_set params['Payload'] = utils.dumps(payload) result = client.invoke(**params) result['Payload'] = result['Payload'].read() if isinstance(result['Payload'], bytes): result['Payload'] = result['Payload'].decode('utf-8') results.append(result) return results def register_action_invoke_lambda(registry, _): for resource in registry.keys(): klass = registry.get(resource) klass.action_registry.register('invoke-lambda', LambdaInvoke) resources.subscribe(resources.EVENT_FINAL, register_action_invoke_lambda)
'Key': 'ResourceId', 'Operator': 'Contains', 'Values': [r[self.manager.resource_type.id] for r in resources] }) return {'OpsItemFilters': q} @classmethod def register(cls, registry, _): for resource in registry.keys(): klass = registry.get(resource) klass.filter_registry.register('ops-item', cls) resources.subscribe(resources.EVENT_FINAL, OpsItemFilter.register) class PostItem(Action): """Post an OpsItem to AWS Systems Manager OpsCenter Dashboard. https://docs.aws.amazon.com/systems-manager/latest/userguide/OpsCenter.html Each ops item supports up to a 100 associated resources. This action supports the builtin OpsCenter dedup logic with additional support for associating new resources to existing Open ops items. : Example : Create an ops item for ec2 instances with Create User permissions
queue_url = "https://sqs.%s.amazonaws.com/%s/%s" % ( region, owner_id, queue_name) else: region = self.manager.config.region owner_id = self.manager.config.account_id queue_name = queue queue_url = "https://sqs.%s.amazonaws.com/%s/%s" % ( region, owner_id, queue_name) client = self.manager.session_factory( region=region, assume=self.assume_role).client('sqs') attrs = { 'mtype': { 'DataType': 'String', 'StringValue': self.C7N_DATA_MESSAGE, }, } result = client.send_message(QueueUrl=queue_url, MessageBody=self.pack(message), MessageAttributes=attrs) return result['MessageId'] @classmethod def register_resource(cls, registry, resource_class): if 'notify' in resource_class.action_registry: return resource_class.action_registry.register('notify', cls) aws_resources.subscribe(Notify.register_resource)
'Timestamp': now, 'Value': value, # TODO: support an operation of 'stats' to include this # structure instead of a single Value # Value and StatisticValues are mutually exclusive. # 'StatisticValues': { # 'SampleCount': 1, # 'Sum': 123.0, # 'Minimum': 123.0, # 'Maximum': 123.0 # }, 'Unit': units, }, ] client = utils.local_session( self.manager.session_factory).client('cloudwatch') client.put_metric_data(Namespace=ns, MetricData=metrics_data) return resources def register_action_put_metric(registry, _): # apply put metric to each resource for resource in registry.keys(): klass = registry.get(resource) klass.action_registry.register('put-metric', PutMetric) resources.subscribe(resources.EVENT_FINAL, register_action_put_metric)
if not tag_already_set: untagged_resources.append(resource) # if update is set to True, we will overwrite the userName tag even if # the user already set a value else: untagged_resources = resources tag_action = self.manager.action_registry.get('tag') new_tags = {self.data['tag']: user} # if principal_id_key is set (and value), we'll set the principalId tag. principal_id_key = self.data.get('principal_id_tag', None) if principal_id_key and principal_id_value: new_tags[principal_id_key] = principal_id_value for key, value in six.iteritems(new_tags): tag_action({ 'key': key, 'value': value }, self.manager).process(untagged_resources) return new_tags def register_action_tag_user(registry, _): for resource in registry.keys(): klass = registry.get(resource) if klass.action_registry.get( 'tag') and not klass.action_registry.get('auto-tag-user'): klass.action_registry.register('auto-tag-user', AutoTagUser) resources.subscribe(resources.EVENT_FINAL, register_action_tag_user)
aws.shape_validate(query, self.query_shape, 'securityhub') def process(self, resources, event=None): client = local_session( self.manager.session_factory).client( 'securityhub', region_name=self.data.get('region')) found = [] params = dict(self.data.get('query', {})) for r_arn, resource in zip(self.manager.get_arns(resources), resources): params['ResourceId'] = [{"Value": r_arn, "Comparison": "EQUALS"}] findings = client.get_findings(Filters=params).get("Findings") if len(findings) > 0: resource[self.annotation_key] = findings found.append(resource) return found @classmethod def register_resources(klass, registry, resource_class): """ meta model subscriber on resource registration. SecurityHub Findings Filter """ for rtype, resource_manager in registry.items(): if 'post-finding' in resource_manager.action_registry: continue resource_class.filter_registry.register('finding', klass) resources.subscribe(resources.EVENT_REGISTER, SecurityHubFindingFilter.register_resources)
r_id = manager.resource_type.id # TODO only fetch resource with the given ids. return { r[r_id]: {t['Key']: t['Value'] for t in r.get('Tags', [])} for r in manager.resources() if r[r_id] in ids } @classmethod def register_resources(klass, registry, resource_class): if not resource_class.action_registry.get('tag'): return resource_class.action_registry.register('copy-related-tag', klass) aws_resources.subscribe(aws_resources.EVENT_REGISTER, CopyRelatedResourceTag.register_resources) def universal_retry(method, ResourceARNList, **kw): """Retry support for resourcegroup tagging apis. The resource group tagging api typically returns a 200 status code with embedded resource specific errors. To enable resource specific retry on throttles, we extract those, perform backoff w/ jitter and continue. Other errors are immediately raised. We do not aggregate unified resource responses across retries, only the last successful response is returned for a subset of the resources if a retry is performed. """ max_attempts = 6
client = utils.local_session(self.manager.session_factory).client( 'lambda', config=config) payload = { 'version': VERSION, 'event': event, 'action': self.data, 'policy': self.manager.data } results = [] for resource_set in utils.chunks(resources, self.data.get('batch_size', 250)): payload['resources'] = resource_set params['Payload'] = utils.dumps(payload) result = client.invoke(**params) result['Payload'] = result['Payload'].read() if isinstance(result['Payload'], bytes): result['Payload'] = result['Payload'].decode('utf-8') results.append(result) return results def register_action_invoke_lambda(registry, _): for resource in registry.keys(): klass = registry.get(resource) klass.action_registry.register('invoke-lambda', LambdaInvoke) resources.subscribe(resources.EVENT_FINAL, register_action_invoke_lambda)
else: continue details[k] = v[:SECHUB_VALUE_SIZE_LIMIT] details['c7n:resource-type'] = self.manager.type other = { 'Type': 'Other', 'Id': self.manager.get_arns([r])[0], 'Region': self.manager.config.region, 'Details': { 'Other': filter_empty(details) } } tags = {t['Key']: t['Value'] for t in r.get('Tags', [])} if tags: other['Tags'] = tags return other @classmethod def register_resource(klass, registry, event): for rtype, resource_manager in registry.items(): if not resource_manager.has_arn(): continue if 'post-finding' in resource_manager.action_registry: continue resource_manager.action_registry.register('post-finding', klass) aws_resources.subscribe(aws_resources.EVENT_FINAL, OtherResourcePostFinding.register_resource)
for batch_rset in chunks(resource_set, self.data.get('batch-size', 250)): pinput['resources'] = [rarn for rarn, _ in batch_rset] params['input'] = dumps(pinput) exec_arn = self.manager.retry(client.start_execution, **params).get('executionArn') for _, r in resource_set: r['c7n:execution-arn'] = exec_arn @classmethod def register(cls, registry, key): for _, r in registry.items(): r.action_registry.register('invoke-sfn', cls) resources.subscribe(resources.EVENT_FINAL, InvokeStepFunction.register) @StepFunction.action_registry.register('tag') class TagStepFunction(Tag): """Action to create tag(s) on a step function :example: .. code-block:: yaml policies: - name: tag-step-function resource: step-machine actions: - type: tag
q.append({ 'Key': 'ResourceId', 'Operator': 'Contains', 'Values': [r[self.manager.resource_type.id] for r in resources] }) return {'OpsItemFilters': q} @classmethod def register_resource(cls, registry, resource_class): if 'ops-item' not in resource_class.filter_registry: resource_class.filter_registry.register('ops-item', cls) resources.subscribe(OpsItemFilter.register_resource) class PostItem(Action): """Post an OpsItem to AWS Systems Manager OpsCenter Dashboard. https://docs.aws.amazon.com/systems-manager/latest/userguide/OpsCenter.html Each ops item supports up to a 100 associated resources. This action supports the builtin OpsCenter dedup logic with additional support for associating new resources to existing Open ops items. : Example : Create an ops item for ec2 instances with Create User permissions
client = local_session(self.manager.session_factory).client( 'securityhub', region_name=self.data.get('region')) found = [] params = dict(self.data.get('query', {})) for r_arn, resource in zip(self.manager.get_arns(resources), resources): params['ResourceId'] = [{"Value": r_arn, "Comparison": "EQUALS"}] findings = client.get_findings(Filters=params).get("Findings") if len(findings) > 0: resource[self.annotation_key] = findings found.append(resource) return found @classmethod def register_resources(klass, registry, resource_class): """ meta model subscriber on resource registration. SecurityHub Findings Filter """ for rtype, resource_manager in registry.items(): if not resource_manager.has_arn(): continue if 'post-finding' in resource_manager.action_registry: continue resource_class.filter_registry.register('finding', klass) resources.subscribe(resources.EVENT_REGISTER, SecurityHubFindingFilter.register_resources)
tag_action({ 'key': key, 'value': value }, self.manager).process(untagged_resources) return new_tags def add_auto_tag_user(registry, _): for resource in registry.keys(): klass = registry.get(resource) if klass.action_registry.get( 'tag') and not klass.action_registry.get('auto-tag-user'): klass.action_registry.register('auto-tag-user', AutoTagUser) resources.subscribe(resources.EVENT_FINAL, add_auto_tag_user) class PutMetric(BaseAction): """Action to put metrics based on an expression into CloudWatch metrics :example: .. code-block:: yaml policies: - name: track-attached-ebs resource: ec2 comment: | Put the count of the number of EBS attached disks to an instance filters:
def process_event(self, client, health_events): entities = [] for event_set in chunks(health_events, 10): event_map = {e['arn']: e for e in event_set} event_arns = list(event_map.keys()) for d in client.describe_event_details( eventArns=event_arns).get('successfulSet', ()): event_map[d['event']['arn']]['Description'] = d[ 'eventDescription']['latestDescription'] paginator = client.get_paginator('describe_affected_entities') entities.extend(list(itertools.chain( *[p['entities'] for p in paginator.paginate( filter={'eventArns': event_arns})]))) return entities @classmethod def register_resources(klass, registry, resource_class): """ meta model subscriber on resource registration. We watch for PHD event that provides affected entities and register the health-event filter to the resources. """ services = {'acm-certificate', 'directconnect', 'dms-instance', 'directory', 'ec2', 'dynamodb-table', 'cache-cluster', 'efs', 'app-elb', 'elb', 'emr', 'rds', 'storage-gateway'} if resource_class.type in services: resource_class.filter_registry.register('health-event', klass) resources.subscribe(resources.EVENT_REGISTER, HealthEventFilter.register_resources)