Esempio n. 1
0
            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)
Esempio n. 2
0
                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)
Esempio n. 3
0
    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
Esempio n. 4
0
                        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)
Esempio n. 5
0
            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)
Esempio n. 6
0
            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)
Esempio n. 7
0
            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)
Esempio n. 8
0
        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)
Esempio n. 9
0
            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)
Esempio n. 10
0
        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)
Esempio n. 11
0
        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)
Esempio n. 12
0
            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)
Esempio n. 13
0
        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)
Esempio n. 14
0
                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)
Esempio n. 15
0
        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
Esempio n. 16
0
                    '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)
Esempio n. 17
0
                '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)
Esempio n. 18
0
        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
Esempio n. 19
0
        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:
Esempio n. 20
0
    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)
Esempio n. 21
0
            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)
Esempio n. 22
0
            '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
Esempio n. 23
0
            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)
Esempio n. 24
0
                '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)
Esempio n. 25
0
                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)
Esempio n. 26
0
            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)
Esempio n. 27
0
        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
Esempio n. 28
0
        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)
Esempio n. 29
0
            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)
Esempio n. 30
0
        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
Esempio n. 31
0
        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
Esempio n. 32
0
        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)
Esempio n. 33
0
            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:
Esempio n. 34
0
    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)