Beispiel #1
0
    def ensure_regex_pattern_present(self, regex_pattern):
        name = regex_pattern['name']

        pattern_set = self.get_regex_pattern_by_name(name)
        if not pattern_set:
            pattern_set = self.client.create_regex_pattern_set(
                Name=name,
                ChangeToken=get_change_token(self.client,
                                             self.module))['RegexPatternSet']
        missing = set(regex_pattern['regex_strings']) - set(
            pattern_set['RegexPatternStrings'])
        extra = set(pattern_set['RegexPatternStrings']) - set(
            regex_pattern['regex_strings'])
        if not missing and not extra:
            return pattern_set
        updates = [{
            'Action': 'INSERT',
            'RegexPatternString': pattern
        } for pattern in missing]
        updates.extend([{
            'Action': 'DELETE',
            'RegexPatternString': pattern
        } for pattern in extra])
        self.client.update_regex_pattern_set(
            RegexPatternSetId=pattern_set['RegexPatternSetId'],
            Updates=updates,
            ChangeToken=get_change_token(self.client, self.module))
        return self.get_regex_pattern_set_with_backoff(
            pattern_set['RegexPatternSetId'])['RegexPatternSet']
Beispiel #2
0
def ensure_web_acl_present(client, module):
    changed = False
    result = None
    name = module.params['name']
    web_acl_id = get_web_acl_by_name(client, module, name)
    if web_acl_id:
        (changed, result) = find_and_update_web_acl(client, module, web_acl_id)
    else:
        metric_name = module.params['metric_name']
        if not metric_name:
            metric_name = re.sub(r'[^A-Za-z0-9]', '', module.params['name'])
        default_action = module.params['default_action'].upper()
        try:
            new_web_acl = client.create_web_acl(
                Name=name,
                MetricName=metric_name,
                DefaultAction={'Type': default_action},
                ChangeToken=get_change_token(client, module))
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg='Could not create Web ACL')
        (changed,
         result) = find_and_update_web_acl(client, module,
                                           new_web_acl['WebACL']['WebACLId'])
    return changed, result
Beispiel #3
0
def find_and_update_web_acl(client, module, web_acl_id):
    acl = get_web_acl(client, module, web_acl_id)
    rule_lookup = create_rule_lookup(client, module)
    existing_rules = acl['Rules']
    desired_rules = [{
        'RuleId': rule_lookup[rule['name']]['RuleId'],
        'Priority': rule['priority'],
        'Action': {
            'Type': rule['action'].upper()
        },
        'Type': rule.get('type', 'regular').upper()
    } for rule in module.params['rules']]
    missing = [rule for rule in desired_rules if rule not in existing_rules]
    extras = []
    if module.params['purge_rules']:
        extras = [rule for rule in existing_rules if rule not in desired_rules]

    insertions = [format_for_update(rule, 'INSERT') for rule in missing]
    deletions = [format_for_update(rule, 'DELETE') for rule in extras]
    changed = bool(insertions + deletions)
    if changed:
        try:
            client.update_web_acl(WebACLId=acl['WebACLId'],
                                  ChangeToken=get_change_token(client, module),
                                  Updates=insertions + deletions,
                                  DefaultAction=acl['DefaultAction'])
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg='Could not update Web ACL')
        acl = get_web_acl(client, module, web_acl_id)
    return changed, acl
Beispiel #4
0
 def find_and_delete_condition(self, condition_set_id):
     current_condition = self.get_condition_by_id(condition_set_id)
     in_use_rules = self.find_condition_in_rules(condition_set_id)
     if in_use_rules:
         rulenames = ', '.join(in_use_rules)
         self.module.fail_json(msg="Condition %s is in use by %s" %
                               (current_condition['Name'], rulenames))
     if current_condition[self.conditiontuples]:
         # Filters are deleted using update with the DELETE action
         func = getattr(self.client, 'update_' + self.method_suffix)
         params = self.format_for_deletion(current_condition)
         try:
             func(**params)
         except (botocore.exceptions.ClientError,
                 botocore.exceptions.BotoCoreError) as e:
             self.module.fail_json_aws(
                 e, msg='Could not delete filters from condition')
     func = getattr(self.client, 'delete_' + self.method_suffix)
     params = dict()
     params[self.conditionsetid] = condition_set_id
     params['ChangeToken'] = get_change_token(self.client, self.module)
     try:
         func(**params)
     except (botocore.exceptions.ClientError,
             botocore.exceptions.BotoCoreError) as e:
         self.module.fail_json_aws(e, msg='Could not delete condition')
     # tidy up regex patterns
     if self.type == 'regex':
         self.tidy_up_regex_patterns(current_condition)
     return True, {}
Beispiel #5
0
def remove_rules_from_web_acl(client, module, web_acl_id):
    acl = get_web_acl(client, module, web_acl_id)
    deletions = [format_for_update(rule, 'DELETE') for rule in acl['Rules']]
    try:
        client.update_web_acl(WebACLId=acl['WebACLId'],
                              ChangeToken=get_change_token(client, module),
                              Updates=deletions,
                              DefaultAction=acl['DefaultAction'])
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg='Could not remove rule')
Beispiel #6
0
 def format_for_deletion(self, condition):
     return {
         'ChangeToken':
         get_change_token(self.client, self.module),
         'Updates': [{
             'Action': 'DELETE',
             self.conditiontuple: current_condition_tuple
         } for current_condition_tuple in condition[self.conditiontuples]],
         self.conditionsetid:
         condition[self.conditionsetid]
     }
Beispiel #7
0
    def delete_unused_regex_pattern(self, regex_pattern_set_id):
        try:
            regex_pattern_set = self.client.get_regex_pattern_set(
                RegexPatternSetId=regex_pattern_set_id)['RegexPatternSet']
            updates = list()
            for regex_pattern_string in regex_pattern_set[
                    'RegexPatternStrings']:
                updates.append({
                    'Action': 'DELETE',
                    'RegexPatternString': regex_pattern_string
                })
            self.client.update_regex_pattern_set(
                RegexPatternSetId=regex_pattern_set_id,
                Updates=updates,
                ChangeToken=get_change_token(self.client, self.module))

            self.client.delete_regex_pattern_set(
                RegexPatternSetId=regex_pattern_set_id,
                ChangeToken=get_change_token(self.client, self.module))
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            self.module.fail_json_aws(e, msg='Could not delete regex pattern')
Beispiel #8
0
def remove_rule_conditions(client, module, rule_id):
    conditions = get_rule(client, module, rule_id)['Predicates']
    updates = [
        format_for_deletion(camel_dict_to_snake_dict(condition))
        for condition in conditions
    ]
    try:
        client.update_rule(RuleId=rule_id,
                           ChangeToken=get_change_token(client, module),
                           Updates=updates)
    except (botocore.exceptions.ClientError,
            botocore.exceptions.BotoCoreError) as e:
        module.fail_json_aws(e, msg='Could not remove rule conditions')
Beispiel #9
0
def ensure_web_acl_absent(client, module):
    web_acl_id = get_web_acl_by_name(client, module, module.params['name'])
    if web_acl_id:
        web_acl = get_web_acl(client, module, web_acl_id)
        if web_acl['Rules']:
            remove_rules_from_web_acl(client, module, web_acl_id)
        try:
            client.delete_web_acl(WebACLId=web_acl_id,
                                  ChangeToken=get_change_token(client, module))
            return True, {}
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg='Could not delete Web ACL')
    return False, {}
Beispiel #10
0
 def ensure_condition_present(self):
     name = self.module.params['name']
     condition_set_id = self.get_condition_by_name(name)
     if condition_set_id:
         return self.find_and_update_condition(condition_set_id)
     else:
         params = dict()
         params['Name'] = name
         params['ChangeToken'] = get_change_token(self.client, self.module)
         func = getattr(self.client, 'create_' + self.method_suffix)
         try:
             condition = func(**params)
         except (botocore.exceptions.ClientError,
                 botocore.exceptions.BotoCoreError) as e:
             self.module.fail_json_aws(e, msg='Could not create condition')
         return self.find_and_update_condition(
             condition[self.conditionset][self.conditionsetid])
Beispiel #11
0
def ensure_rule_absent(client, module):
    rule_id = get_rule_by_name(client, module, module.params['name'])
    in_use_web_acls = find_rule_in_web_acls(client, module, rule_id)
    if in_use_web_acls:
        web_acl_names = ', '.join(in_use_web_acls)
        module.fail_json(msg="Rule %s is in use by Web ACL(s) %s" %
                         (module.params['name'], web_acl_names))
    if rule_id:
        remove_rule_conditions(client, module, rule_id)
        try:
            return True, client.delete_rule(RuleId=rule_id,
                                            ChangeToken=get_change_token(
                                                client, module))
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg='Could not delete rule')
    return False, {}
Beispiel #12
0
def ensure_rule_present(client, module):
    name = module.params['name']
    rule_id = get_rule_by_name(client, module, name)
    params = dict()
    if rule_id:
        return find_and_update_rule(client, module, rule_id)
    else:
        params['Name'] = module.params['name']
        metric_name = module.params['metric_name']
        if not metric_name:
            metric_name = re.sub(r'[^a-zA-Z0-9]', '', module.params['name'])
        params['MetricName'] = metric_name
        params['ChangeToken'] = get_change_token(client, module)
        try:
            new_rule = client.create_rule(**params)['Rule']
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg='Could not create rule')
        return find_and_update_rule(client, module, new_rule['RuleId'])
Beispiel #13
0
    def format_for_update(self, condition_set_id):
        # Prep kwargs
        kwargs = dict()
        kwargs['Updates'] = list()

        for filtr in self.module.params.get('filters'):
            # Only for ip_set
            if self.type == 'ip':
                # there might be a better way of detecting an IPv6 address
                if ':' in filtr.get('ip_address'):
                    ip_type = 'IPV6'
                else:
                    ip_type = 'IPV4'
                condition_insert = {
                    'Type': ip_type,
                    'Value': filtr.get('ip_address')
                }

            # Specific for geo_match_set
            if self.type == 'geo':
                condition_insert = dict(Type='Country',
                                        Value=filtr.get('country'))

            # Common For everything but ip_set and geo_match_set
            if self.type not in ('ip', 'geo'):

                condition_insert = dict(FieldToMatch=dict(
                    Type=filtr.get('field_to_match').upper()),
                                        TextTransformation=filtr.get(
                                            'transformation', 'none').upper())

                if filtr.get('field_to_match').upper() == "HEADER":
                    if filtr.get('header'):
                        condition_insert['FieldToMatch']['Data'] = filtr.get(
                            'header').lower()
                    else:
                        self.module.fail_json(
                            msg=str("DATA required when HEADER requested"))

            # Specific for byte_match_set
            if self.type == 'byte':
                condition_insert['TargetString'] = filtr.get('target_string')
                condition_insert['PositionalConstraint'] = filtr.get(
                    'position')

            # Specific for size_constraint_set
            if self.type == 'size':
                condition_insert['ComparisonOperator'] = filtr.get(
                    'comparison')
                condition_insert['Size'] = filtr.get('size')

            # Specific for regex_match_set
            if self.type == 'regex':
                condition_insert[
                    'RegexPatternSetId'] = self.ensure_regex_pattern_present(
                        filtr.get('regex_pattern'))['RegexPatternSetId']

            kwargs['Updates'].append({
                'Action': 'INSERT',
                self.conditiontuple: condition_insert
            })

        kwargs[self.conditionsetid] = condition_set_id
        kwargs['ChangeToken'] = get_change_token(self.client, self.module)
        return kwargs
Beispiel #14
0
def find_and_update_rule(client, module, rule_id):
    rule = get_rule(client, module, rule_id)
    rule_id = rule['RuleId']

    existing_conditions = dict(
        (condition_type, dict()) for condition_type in MATCH_LOOKUP)
    desired_conditions = dict(
        (condition_type, dict()) for condition_type in MATCH_LOOKUP)
    all_conditions = dict()

    for condition_type in MATCH_LOOKUP:
        method = 'list_' + MATCH_LOOKUP[condition_type]['method'] + 's'
        all_conditions[condition_type] = dict()
        try:
            paginator = client.get_paginator(method)
            func = paginator.paginate().build_full_result
        except (KeyError, botocore.exceptions.OperationNotPageableError):
            # list_geo_match_sets and list_regex_match_sets do not have a paginator
            # and throw different exceptions
            func = getattr(client, method)
        try:
            pred_results = func()[MATCH_LOOKUP[condition_type]['conditionset']
                                  + 's']
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e,
                                 msg='Could not list %s conditions' %
                                 condition_type)
        for pred in pred_results:
            pred['DataId'] = pred[MATCH_LOOKUP[condition_type]['conditionset']
                                  + 'Id']
            all_conditions[condition_type][
                pred['Name']] = camel_dict_to_snake_dict(pred)
            all_conditions[condition_type][
                pred['DataId']] = camel_dict_to_snake_dict(pred)

    for condition in module.params['conditions']:
        desired_conditions[condition['type']][condition['name']] = condition

    reverse_condition_types = dict(
        (v['type'], k) for (k, v) in MATCH_LOOKUP.items())
    for condition in rule['Predicates']:
        existing_conditions[reverse_condition_types[condition['Type']]][
            condition['DataId']] = camel_dict_to_snake_dict(condition)

    insertions = list()
    deletions = list()

    for condition_type in desired_conditions:
        for (condition_name,
             condition) in desired_conditions[condition_type].items():
            if condition_name not in all_conditions[condition_type]:
                module.fail_json(msg="Condition %s of type %s does not exist" %
                                 (condition_name, condition_type))
            condition['data_id'] = all_conditions[condition_type][
                condition_name]['data_id']
            if condition['data_id'] not in existing_conditions[condition_type]:
                insertions.append(format_for_insertion(condition))

    if module.params['purge_conditions']:
        for condition_type in existing_conditions:
            deletions.extend([
                format_for_deletion(condition)
                for condition in existing_conditions[condition_type].values()
                if not all_conditions[condition_type][condition['data_id']]
                ['name'] in desired_conditions[condition_type]
            ])

    changed = bool(insertions or deletions)
    if changed:
        try:
            client.update_rule(RuleId=rule_id,
                               ChangeToken=get_change_token(client, module),
                               Updates=insertions + deletions)
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg='Could not update rule conditions')

    return changed, get_rule(client, module, rule_id)