def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.

        raises:
            InvalidRulesSchemaError: if invalid rules definition.
        """
        mode = rule_def.get('mode', '')
        if mode not in _SUPPORTED_MODES:
            raise errors.InvalidRulesSchemaError(
                'Unexpected "mode" in rule {}: got {}, want one of {}'.format(
                    rule_index, mode, _SUPPORTED_MODES))
        if not rule_def.get('resource_types'):
            raise errors.InvalidRulesSchemaError(
                'Missing non empty "resource_types" in rule {}'.format(
                    rule_index))

        resource_tree = ResourceTree.from_json(
            rule_def.get('resource_trees', []))
        self.rules.append(
            Rule(name=rule_def['name'],
                 index=rule_index,
                 resource_types=set(rule_def['resource_types']),
                 resource_tree=resource_tree))
Ejemplo n.º 2
0
    def __init__(self, rule_index, rule_name, permissions, res):
        """Initialize.

        Args:
            rule_index (int): The index of the rule.
            rule_name (str): Name of the rule.
            permissions (int): Expected permissions of the role.
            res (dict): Parent resource of the role that should obey the rule.
        """
        self.rule_name = rule_name
        self.rule_index = rule_index
        self.permissions = permissions[:]
        self.res_types = res[:]

        for index, res_item in enumerate(self.res_types):
            if 'type' not in res_item:
                raise audit_errors.InvalidRulesSchemaError(
                    'Lack of resource:type in rule {}'.format(rule_index))
            if res_item['type'] not in [
                    'organization', 'folder', 'project', 'role'
            ]:
                raise audit_errors.InvalidRulesSchemaError(
                    'Wrong resource:type {} in rule {}'.format(
                        res_item['type'], rule_index))
            if 'resource_ids' not in res_item:
                raise audit_errors.InvalidRulesSchemaError(
                    'Lack of resource:resource_ids in rule {}'.format(
                        rule_index))

            if '*' in res_item['resource_ids']:
                self.res_types[index]['resource_ids'] = ['*']
Ejemplo n.º 3
0
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        if 'name' not in rule_def:
            raise audit_errors.InvalidRulesSchemaError(
                'Lack of role_name in rule {}'.format(rule_index))
        if 'role_name' not in rule_def:
            raise audit_errors.InvalidRulesSchemaError(
                'Lack of role_name in rule {}'.format(rule_index))
        role_name = rule_def['role_name']
        if 'permissions' not in rule_def:
            raise audit_errors.InvalidRulesSchemaError(
                'Lack of permissions in rule {}'.format(rule_index))
        if 'resource' not in rule_def:
            raise audit_errors.InvalidRulesSchemaError(
                'Lack of resource in rule {}'.format(rule_index))
        res = rule_def['resource']

        rule = Rule(rule_index=rule_index,
                    rule_name=rule_def['name'],
                    permissions=rule_def['permissions'],
                    res=res)

        if role_name not in self.rules_map:
            self.rules_map[role_name] = [rule]
        else:
            self.rules_map[role_name].append(rule)
Ejemplo n.º 4
0
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        with self._lock:
            for resource in rule_def.get('resource'):
                resource_ids = resource.get('resource_ids')
                resource_type = None
                try:
                    resource_type = resource_mod.ResourceType.verify(
                        resource.get('type'))
                except resource_errors.InvalidResourceTypeError:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource type in rule {}'.format(rule_index))

                if not resource_ids or len(resource_ids) < 1:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource ids in rule {}'.format(rule_index))

                rule_mode = rule_def.get('mode')
                if rule_mode not in ('blacklist', 'whitelist'):
                    raise audit_errors.InvalidRulesSchemaError(
                        'Unknown mode in rule {}'.format(rule_index))

                rule_key = rule_def.get('key')
                if rule_key is None:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing key in rule {}'.format(rule_index))

                rule_values = rule_def.get('values', [])

                # For each resource id associated with the rule, create a
                # mapping of resource => rules.
                for resource_id in resource_ids:
                    gcp_resource = resource_util.create_resource(
                        resource_id=resource_id, resource_type=resource_type)

                    rule = Rule(
                        rule_def.get('name'),
                        rule_index,
                        rule_mode,
                        rule_key,
                        rule_values,
                    )
                    resource_rules = self.resource_rules_map.setdefault(
                        gcp_resource, ResourceRules(resource=gcp_resource))

                    if rule not in resource_rules.rules:
                        resource_rules.rules.add(rule)
Ejemplo n.º 5
0
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        with self._lock:
            for resource in rule_def.get('resource'):
                resource_ids = resource.get('resource_ids')
                resource_type = None
                try:
                    resource_type = resource_mod.ResourceType.verify(
                        resource.get('type'))
                except resource_errors.InvalidResourceTypeError:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource type in rule {}'.format(rule_index))

                if not resource_ids or len(resource_ids) < 1:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource ids in rule {}'.format(rule_index))

                check_serverconfig_valid_node_versions = rule_def.get(
                    'check_serverconfig_valid_node_versions', False)
                check_serverconfig_valid_master_versions = rule_def.get(
                    'check_serverconfig_valid_master_versions', False)
                allowed_nodepool_versions = rule_def.get(
                    'allowed_nodepool_versions', [])
                allowed_versions = []
                for allowed_version in allowed_nodepool_versions:
                    allowed_versions.append(VersionRule(**allowed_version))

                # For each resource id associated with the rule, create a
                # mapping of resource => rules.
                for resource_id in resource_ids:
                    gcp_resource = resource_util.create_resource(
                        resource_id=resource_id,
                        resource_type=resource_type)

                    rule = Rule(
                        rule_def.get('name'),
                        rule_index,
                        check_serverconfig_valid_node_versions,
                        check_serverconfig_valid_master_versions,
                        allowed_versions)

                    resource_rules = self.resource_rules_map.setdefault(
                        gcp_resource, ResourceRules(resource=gcp_resource))

                    if rule not in resource_rules.rules:
                        resource_rules.rules.add(rule)
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        resources = rule_def.get('resource')
        mode = rule_def.get('mode')
        key = rule_def.get('key')

        if not resources or key is None or mode not in RULE_MODES:
            raise audit_errors.InvalidRulesSchemaError(
                'Faulty rule {}'.format(rule_index))

        for resource in resources:
            resource_type = resource.get('type')
            resource_ids = resource.get('resource_ids')

            if resource_type not in self.supported_resource_types:
                raise audit_errors.InvalidRulesSchemaError(
                    'Invalid resource type in rule {}'.format(rule_index))

            if not resource_ids or len(resource_ids) < 1:
                raise audit_errors.InvalidRulesSchemaError(
                    'Missing resource ids in rule {}'.format(rule_index))

            # For each resource id associated with the rule, create a
            # mapping of resource => rules.
            for resource_id in resource_ids:
                gcp_resource = resource_util.create_resource(
                    resource_id=resource_id,
                    resource_type=resource_type)

                rule_def_resource = {
                    'key': key,
                    'mode': mode
                }
                rule = Rule(rule_name=rule_def.get('name'),
                            rule_index=rule_index,
                            rule=rule_def_resource)

                resource_rules = self.resource_rules_map.setdefault(
                    gcp_resource, ResourceRules(resource=gcp_resource))

                if not resource_rules:
                    self.resource_rules_map[rule_index] = rule
                if rule not in resource_rules.rules:
                    resource_rules.rules.add(rule)
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        with self._lock:
            for resource in rule_def.get('resource'):
                resource_ids = resource.get('resource_ids')
                try:
                    resource_type = resource_mod.ResourceType.verify(
                        resource.get('type'))
                except resource_errors.InvalidResourceTypeError:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource type in rule {}'.format(rule_index))

                if not resource_ids or len(resource_ids) < 1:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource ids in rule {}'.format(rule_index))
                key_max_age_str = rule_def.get('max_age', None)

                try:
                    key_max_age = int(key_max_age_str)
                except (ValueError, TypeError):
                    raise audit_errors.InvalidRulesSchemaError(
                        'Service account key "max_age" missing or not an '
                        'integer in rule {}'.format(rule_index))

                # For each resource id associated with the rule, create a
                # mapping of resource => rules.
                for resource_id in resource_ids:
                    gcp_resource = resource_util.create_resource(
                        resource_id=resource_id,
                        resource_type=resource_type)

                    rule = Rule(
                        rule_def.get('name'),
                        rule_index,
                        key_max_age)

                    resource_rules = self.resource_rules_map.setdefault(
                        gcp_resource, ResourceRules(resource=gcp_resource))

                    if rule not in resource_rules.rules:
                        resource_rules.rules.add(rule)
Ejemplo n.º 8
0
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        mode = rule_def.get('mode')
        settings = rule_def.get('settings')
        groups_emails = rule_def.get('groups_emails')
        only_iam_groups = rule_def.get('only_iam_groups')

        if (settings is None or only_iam_groups is None or not groups_emails
                or mode not in RULE_MODES):
            raise audit_errors.InvalidRulesSchemaError(
                'Faulty rule {}'.format(rule_index))

        for rule_setting in settings:
            if rule_setting not in self.supported_settings:
                raise audit_errors.InvalidRulesSchemaError(
                    'Faulty rule {}'.format(rule_index))

        for group_email in groups_emails:
            # For each resource id associated with the rule, create a
            # mapping of resource => rules.
            gcp_resource = resource_util.create_resource(
                resource_id=group_email,
                resource_type=resource.ResourceType.GROUPS_SETTINGS)

            rule_def_resource = {
                'settings': settings,
                'mode': mode,
                'only_iam_groups': only_iam_groups
            }
            rule = Rule(rule_name=rule_def.get('name'),
                        rule_index=rule_index,
                        rule=rule_def_resource)

            resource_rules = self.resource_rules_map.setdefault(
                gcp_resource, ResourceRules(_resource=gcp_resource))

            if only_iam_groups:
                if rule not in resource_rules.iam_only_rules:
                    resource_rules.iam_only_rules.add(rule)
            elif rule not in resource_rules.not_iam_only_rules:
                resource_rules.not_iam_only_rules.add(rule)
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        resources = rule_def.get('resource')

        for resource in resources:
            resource_ids = resource.get('resource_ids')

            if not resource_ids or len(resource_ids) < 1:
                raise audit_errors.InvalidRulesSchemaError(
                    'Missing resource ids in rule {}'.format(rule_index))

            bucket = rule_def.get('bucket')
            entity = rule_def.get('entity')
            email = rule_def.get('email')
            domain = rule_def.get('domain')
            role = rule_def.get('role')

            if ((bucket is None) or (entity is None) or (email is None) or
                    (domain is None) or (role is None)):
                raise audit_errors.InvalidRulesSchemaError(
                    'Faulty rule {}'.format(rule_def.get('name')))

            rule_def_resource = BucketAccessControls(
                project_id='',
                bucket=escape_and_globify(bucket),
                full_name='',
                entity=escape_and_globify(entity),
                email=escape_and_globify(email),
                domain=escape_and_globify(domain),
                role=escape_and_globify(role.upper()),
                raw_json=json.dumps(rule_def, sort_keys=True)
            )

            rule = Rule(rule_name=rule_def.get('name'),
                        rule_index=rule_index,
                        rules=rule_def_resource)

            resource_rules = self.resource_rules_map.get(rule_index)

            if not resource_rules:
                self.resource_rules_map[rule_index] = rule
Ejemplo n.º 10
0
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        resources = rule_def.get('resource')

        for raw_resource in resources:
            resource_ids = raw_resource.get('resource_ids')

            if not resource_ids or len(resource_ids) < 1:
                raise audit_errors.InvalidRulesSchemaError(
                    'Missing resource ids in rule {}'.format(rule_index))

            rule = self._build_rule(rule_def, rule_index)

            resource_type = raw_resource.get('type')
            for resource_id in resource_ids:
                resource = resource_util.create_resource(
                    resource_id=resource_id,
                    resource_type=resource_type,
                )
                self.resource_rules_map[resource].append(rule)
Ejemplo n.º 11
0
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        resources = rule_def.get('resource')

        for resource in resources:
            resource_ids = resource.get('resource_ids')

            if not resource_ids or len(resource_ids) < 1:
                raise audit_errors.InvalidRulesSchemaError(
                    'Missing resource ids in rule {}'.format(rule_index))

            instance_name = rule_def.get('instance_name')
            authorized_networks = rule_def.get('authorized_networks')
            require_ssl = rule_def.get('ssl_enabled', '').lower() == 'true'

            if instance_name is None or authorized_networks is None:
                raise audit_errors.InvalidRulesSchemaError(
                    'Faulty rule {}'.format(rule_def.get('name')))

            rule_def_resource = CloudSqlAccessControl(
                project_id='',
                instance_name=escape_and_globify(instance_name),
                full_name='',
                ipv4_enabled=True,
                authorized_networks=escape_and_globify(authorized_networks),
                require_ssl=require_ssl,
                raw_json=json.dumps(rule_def, sort_keys=True)
            )

            rule = Rule(rule_name=rule_def.get('name'),
                        rule_index=rule_index,
                        rules=rule_def_resource)

            resource_rules = self.resource_rules_map.get(rule_index)

            if not resource_rules:
                self.resource_rules_map[rule_index] = rule
    def create_and_add_rule(self, rule_def, rule_index, apply_to,
                            min_retention, max_retention):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
            apply_to (str): The resource type that the rule is applied to
            min_retention(int): minimum value of the age in lifecycle
            max_retention(int): maximum value of the age in lifecycle
        """
        if 'resource' not in rule_def:
            raise audit_errors.InvalidRulesSchemaError(
                'Lack of resource in rule {}'.format(rule_index))
        resources = rule_def['resource']

        for res in resources:
            if 'type' not in res:
                raise audit_errors.InvalidRulesSchemaError(
                    'Lack of type in rule {}'.format(rule_index))
            resource_type = res['type']

            if 'resource_ids' not in res:
                raise audit_errors.InvalidRulesSchemaError(
                    'Lack of resource_ids in rule {}'.format(rule_index))
            resource_ids = res['resource_ids']

            rule = Rule(rule_name=rule_def.get('name'),
                        rule_index=rule_index,
                        min_retention=min_retention,
                        max_retention=max_retention)

            for rid in resource_ids:
                if rid == '*':
                    raise audit_errors.InvalidRulesSchemaError(
                        'The symbol * is not allowed in rule {}'.format(
                            rule_index))

                gcp_resource = resource_util.create_resource(
                    resource_id=rid, resource_type=resource_type)

                self.resource_rules_map[apply_to][gcp_resource].add(rule)
    def validate_ancestor(self, ancestor, rule_index):
        """Validate the ancestor in a rule.

        Args:
            ancestor (str): The ancestor defined by the rule.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.

        """

        if not ancestor:
            raise audit_errors.InvalidRulesSchemaError(
                'Missing ancestor in rule {}'.format(rule_index))

        ancestor_result = self.ancestor_pattern.match(ancestor)

        if not ancestor_result:
            message = ('Ancestor in rule {} must start with '
                       '\"organizations/\" or \"folders/\"').format(rule_index)
            raise audit_errors.InvalidRulesSchemaError(message)
Ejemplo n.º 14
0
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        resources = rule_def.get('resource')
        if not resources:
            raise errors.InvalidRulesSchemaError(
                'Missing field "resource" in rule {}'.format(rule_index))

        for raw_resource in resources:
            resource_ids = raw_resource.get('resource_ids')

            if not resource_ids:
                raise errors.InvalidRulesSchemaError(
                    'Missing resource ids in rule {}'.format(rule_index))

            resource_type = raw_resource.get('type')

            if resource_type not in ['project', 'folder', 'organization']:
                raise errors.InvalidRulesSchemaError(
                    'Invalid resource type "{}" in rule {}'.format(
                        resource_type, rule_index))

            for resource_id in resource_ids:
                resource = resource_util.create_resource(
                    resource_id=resource_id,
                    resource_type=resource_type,
                )
                if not resource:
                    raise errors.InvalidRulesSchemaError(
                        'Invalid resource in rule {} (id: {}, type: {})'.
                        format(rule_index, resource_id, resource_type))

                rule = self._build_rule(rule_def, rule_index)
                self.resource_to_rules[resource].append(rule)
    def _build_rule(cls, rule_def, rule_index):
        """Build a rule.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.

        Returns:
            Rule: rule for the given definition.
        """
        for field in ['name', 'mode', 'applies_to', 'locations']:
            if field not in rule_def:
                raise errors.InvalidRulesSchemaError(
                    'Missing field "{}" in rule {}'.format(field, rule_index))

        applies_to = {}

        for applies_dict in rule_def.get('applies_to'):
            # For backwards compatibility for when applies_to was a string.
            if isinstance(applies_dict, str):
                applies_dict = {'type': applies_dict, 'resource_ids': ['*']}

            resource_type = applies_dict['type']

            if resource_type != '*' and (
                    resource_type not in SUPPORTED_LOCATION_RESOURCE_TYPES):
                raise errors.InvalidRulesSchemaError(
                    'Unsupported applies to type "{}" in rule {}'.format(
                        resource_type, rule_index))

            applies_to[resource_type] = applies_dict['resource_ids']

        return Rule(name=rule_def.get('name'),
                    index=rule_index,
                    mode=Mode(rule_def.get('mode')),
                    applies_to=applies_to,
                    location_patterns=rule_def.get('locations'))
def get_retention_range(rule_def, rule_index):
    """Get the min and max value of the retention.

    Args:
        rule_def (dict): A dictionary containing rule definition properties.
        rule_index (int): The index of the rule from the rule definitions.
            Assigned automatically when the rule book is built.

    Returns:
        pair: the minimum and maximum value of the Age.
    """
    minimum_retention = rule_def.get('minimum_retention')
    maximum_retention = rule_def.get('maximum_retention')
    if minimum_retention is None and maximum_retention is None:
        raise audit_errors.InvalidRulesSchemaError(
            'Lack of minimum_retention and '
            'maximum_retention in rule {}'.format(rule_index))
    elif minimum_retention != None and maximum_retention != None:
        if minimum_retention > maximum_retention:
            raise audit_errors.InvalidRulesSchemaError(
                'minimum_retention larger than '
                'maximum_retention in rule {}'.format(rule_index))
    return minimum_retention, maximum_retention
    def validate_user(self, user, rule_index):
        """Validate a user in a rule.  Must be an e-mail address
        Args:
            user (str): A user defined by the rule
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """

        email_result = self.email_pattern.match(user)

        if not email_result:
            message = ('User {} in rule {} must be a properly'
                       'formatted e-mail address').format(user, rule_index)
            raise audit_errors.InvalidRulesSchemaError(message)
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        self._rules_sema.acquire()
        try:
            applies_to = rule_def.get('applies_to')
            if applies_to is None:
                raise audit_errors.InvalidRulesSchemaError(
                    'Lack of applies_to in rule {}'.format(rule_index))

            minimum_retention, maximum_retention = get_retention_range(
                rule_def, rule_index)

            if any(support_type not in SUPPORTED_RETENTION_RES_TYPES
                   for support_type in applies_to):
                raise audit_errors.InvalidRulesSchemaError(
                    'Invalid applies_to resource in rule {}'.format(
                        rule_index))

            added_applies_to = set()

            for appto in applies_to:
                if appto in added_applies_to:
                    raise audit_errors.InvalidRulesSchemaError(
                        'redundant applies_to in rule {}'.format(rule_index))
                added_applies_to.add(appto)

                self.create_and_add_rule(rule_def, rule_index, appto,
                                         minimum_retention, maximum_retention)
        finally:
            self._rules_sema.release()
Ejemplo n.º 19
0
    def verify(cls, applies_to):
        """Verify whether the applies_to is valid.

        Args:
            applies_to (str): What the rule applies to.

        Returns:
            str: The applies_to property.

        Raises:
            InvalidRulesSchemaError if applies_to is not valid.
        """
        if applies_to not in cls.apply_types:
            raise audit_errors.InvalidRulesSchemaError(
                'Invalid applies_to: {}'.format(applies_to))
        return applies_to
Ejemplo n.º 20
0
    def verify(cls, mode):
        """Verify whether the mode is valid.

        Args:
            mode (str): The rules mode.

        Returns:
            str: The rules mode property.

        Raises:
            InvalidRulesSchemaError if mode is not valid.
        """
        if mode not in cls.modes:
            raise audit_errors.InvalidRulesSchemaError(
                'Invalid rule mode: {}'.format(mode))
        return mode
Ejemplo n.º 21
0
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.

        Raises:
            InvalidRulesSchemaError: if rule has format error
        """
        target = rule_def.get('target')
        mode = rule_def.get('mode')
        load_balancing_scheme = rule_def.get('load_balancing_scheme')
        port_range = rule_def.get('port_range')
        port = rule_def.get('port')
        ip_address = rule_def.get('ip_address')
        ip_protocol = rule_def.get('ip_protocol')
        if ((target is None) or (mode is None)
                or (load_balancing_scheme is None) or (ip_address is None)
                or (ip_protocol is None)):
            raise audit_errors.InvalidRulesSchemaError('Faulty rule {}'.format(
                rule_def.get('name')))
        rule_def_resource = {
            'target': target,
            'mode': mode,
            'load_balancing_scheme': load_balancing_scheme,
            'port_range': port_range,
            'ip_address': ip_address,
            'ip_protocol': ip_protocol,
            'port': port,
            'full_name': ''
        }

        rule = Rule(rule_name=rule_def.get('name'),
                    rule_index=rule_index,
                    rules=rule_def_resource)

        resource_rules = self.resource_rules_map.get(rule_index)
        if not resource_rules:
            self.resource_rules_map[rule_index] = rule
    def _build_rule(cls, rule_def, rule_index):
        """Build a rule.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.

        Returns:
            Rule: rule for the given definition.
        """
        for field in ['name', 'restrictions']:
            if field not in rule_def:
                raise errors.InvalidRulesSchemaError(
                    'Missing field "{}" in rule {}'.format(field, rule_index))

        return Rule(name=rule_def.get('name'),
                    index=rule_index,
                    restrictions=rule_def.get('restrictions'))
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        The rule supplied to this method is the dictionary parsed from
        the rules definition file.

        For example, this rule...

            # rules yaml:
            rules:
              - name: a rule
                resource:
                  - type: project
                    resource_ids:
                      - my-project-123
                service: allServices
                log_types:
                  - 'ADMIN_READ'
                  - 'DATA_WRITE'
                allowed_exemptions:
                  - 'user:[email protected]'
                  - 'user:[email protected]'

        ... gets parsed into:

            {
                'name': 'a rule',
                'resource': {
                    'type': 'project',
                    'resource_ids': ['my-project-id']
                },
                'service': 'allServices',
                'log_types': [
                    'ADMIN_READ',
                    'DATA_WRITE',
                ],
                'allowed_exemptions': [
                    'user:[email protected]',
                    'user:[email protected]',
                ]
            }

        Args:
            rule_def (dict): Contains rule definition properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        self._rules_sema.acquire()

        try:
            resources = rule_def.get('resource')
            service = rule_def.get('service')
            log_types = rule_def.get('log_types')
            # allowed_exemptions is optional.
            allowed_exemptions = set(rule_def.get('allowed_exemptions', []))
            if not resources or not service or not log_types:
                raise audit_errors.InvalidRulesSchemaError(
                    'Faulty rule {}'.format(rule_index))

            for resource in resources:
                resource_ids = resource.get('resource_ids')
                resource_type = resource.get('type')
                if resource_type not in self.supported_resource_types:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Invalid resource type in rule {}'.format(rule_index))

                if not resource_ids:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource ids in rule {}'.format(rule_index))

                # For each resource id associated with the rule, create a
                # mapping of resource => rules.
                for resource_id in resource_ids:
                    if resource_id == '*' and resource_type != 'project':
                        raise audit_errors.InvalidRulesSchemaError(
                            'Wild-card must use project type in rule {}'.
                            format(rule_index))
                    gcp_resource = resource_util.create_resource(
                        resource_id=resource_id, resource_type=resource_type)

                    rule_def_resource = {
                        'service': service,
                        'log_types': log_types,
                        'allowed_exemptions': allowed_exemptions,
                    }
                    rule = Rule(rule_name=rule_def.get('name'),
                                rule_index=rule_index,
                                rule=rule_def_resource)

                    # If no mapping exists, create it. If the rule isn't in the
                    # mapping, add it.
                    self.resource_rules_map[gcp_resource].add(rule)

        finally:
            self._rules_sema.release()
Ejemplo n.º 24
0
    def add_rule(self, rule_def, rule_index):  # pylint: disable=too-many-locals
        """Add a rule to the rule book.

        Args:
            rule_def (dict): rule definition properties
            rule_index (int): index of the rule from the rule definitions,
                              assigned automatically when the rule book is built
        """
        self._rules_sema.acquire()

        try:
            for resource in rule_def.get('resource'):
                resource_ids = resource.get('resource_ids')
                resource_type = None
                try:
                    resource_type = resource_mod.ResourceType.verify(
                        resource.get('type'))
                except resource_errors.InvalidResourceTypeError:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource type in rule {}'.format(rule_index))

                if not resource_ids or len(resource_ids) < 1:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource ids in rule {}'.format(rule_index))

                allowed_alternate_services = [
                    regular_exp.escape_and_globify(glob) for glob in
                    rule_def.get('allowed_alternate_services', '').split(',')
                    if glob
                ]
                allowed_direct_access_sources = [
                    regular_exp.escape_and_globify(glob)
                    for glob in rule_def.get('allowed_direct_access_sources',
                                             '').split(',') if glob
                ]
                allowed_iap_enabled = regular_exp.escape_and_globify(
                    rule_def.get('allowed_iap_enabled', '*'))

                # For each resource id associated with the rule, create a
                # mapping of resource => rules.
                for resource_id in resource_ids:
                    gcp_resource = resource_util.create_resource(
                        resource_id=resource_id, resource_type=resource_type)

                    rule = Rule(
                        rule_name=rule_def.get('name'),
                        rule_index=rule_index,
                        allowed_alternate_services=allowed_alternate_services,
                        allowed_direct_access_sources=(
                            allowed_direct_access_sources),
                        allowed_iap_enabled=allowed_iap_enabled)

                    rule_applies_to = resource.get('applies_to')
                    rule_key = (gcp_resource, rule_applies_to)

                    # See if we have a mapping of the resource and rule
                    resource_rules = self.resource_rules_map.get(rule_key)

                    # If no mapping exists, create it.
                    if not resource_rules:
                        resource_rules = ResourceRules(
                            resource=gcp_resource,
                            applies_to=rule_applies_to,
                            inherit_from_parents=rule_def.get(
                                'inherit_from_parents', False))
                        self.resource_rules_map[rule_key] = resource_rules

                    # If the rule isn't in the mapping, add it.
                    if rule not in resource_rules.rules:
                        resource_rules.rules.add(rule)
        finally:
            self._rules_sema.release()
Ejemplo n.º 25
0
    def _build_rule(cls, rule_def, rule_index):
        """Build a rule.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.

        Returns:
            Rule: rule for the given definition.
        """
        dataset_ids = []
        for dataset_id in rule_def.get('dataset_ids', []):
            dataset_ids.append(regular_exp.escape_and_globify(dataset_id))

        # Check `dataset_id` for backwards compatibility.
        # TODO: stop supporting this.
        if 'dataset_id' in rule_def:
            dataset_ids.append(
                regular_exp.escape_and_globify(rule_def['dataset_id']))

        if not dataset_ids:
            raise audit_errors.InvalidRulesSchemaError(
                'Missing dataset_ids in rule {}'.format(rule_index))

        bindings = []

        # TODO: stop supporting this.
        binding = cls._get_binding_from_old_syntax(rule_def)
        if binding:
            bindings.append(binding)

        # Default mode to blacklist for backwards compatibility as that was
        # the behaviour before mode was configurable.
        # TODO: make mode required?
        mode = Mode(rule_def.get('mode', 'blacklist'))

        for raw_binding in rule_def.get('bindings', []):
            if 'role' not in raw_binding:
                raise audit_errors.InvalidRulesSchemaError(
                    'Missing role in binding in rule {}'.format(rule_index))
            role = regular_exp.escape_and_globify(raw_binding['role'])

            if 'members' not in raw_binding:
                raise audit_errors.InvalidRulesSchemaError(
                    'Missing members in binding in rule {}'.format(rule_index))

            members = []
            for raw_member in raw_binding['members']:
                fields = {
                    field:
                    regular_exp.escape_and_globify(raw_member.get(field))
                    for field in
                    ['domain', 'group_email', 'user_email', 'special_group']
                }

                # only one key should be set per member
                num_fields_set = sum(
                    [val is not None for val in list(fields.values())])
                if num_fields_set != 1:
                    raise audit_errors.InvalidRulesSchemaError(
                        'At most one member field may be set in rule {}'.
                        format(rule_index))
                members.append(Member(**fields))

            bindings.append(Binding(role, members))

        if not bindings:
            raise audit_errors.InvalidRulesSchemaError(
                'Missing bindings in rule {}'.format(rule_index))

        return Rule(rule_name=rule_def.get('name'),
                    rule_index=rule_index,
                    rule_reference=RuleReference(dataset_ids=dataset_ids,
                                                 bindings=bindings,
                                                 mode=mode))
Ejemplo n.º 26
0
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        The rule supplied to this method is the dictionary parsed from
        the rules definition file.

        For example, this rule...

            # rules yaml:
            rules:
              - name: a rule
                mode: required
                resource:
                  - type: organization
                    applies_to: children
                    resource_ids:
                      - 11223344
                sink:
                  - destination: 'bigquery.googleapis.com/projects/my-proj/*'
                    filter: 'logName:"logs/cloudaudit.googleapis.com"'
                    include_children: '*'

        ... gets parsed into:

            {
                'name': 'a rule',
                'mode': 'required',
                'resource': [{
                    'type': 'organization',
                    'applies_to': 'children',
                    'resource_ids': ['11223344']
                }],
                'sink': {
                    'destination': 'bigquery.googleapis.com/projects/my-proj/*',
                    'filter': logName:"logs/cloudaudit.googleapis.com"',
                    'include_children': '*'
                }
            }

        Args:
            rule_def (dict): Contains rule definition properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        self._rules_sema.acquire()

        try:
            resources = rule_def.get('resource')
            mode = rule_def.get('mode')
            sink = _parse_sink_rule_spec(rule_def.get('sink'))

            if not resources or sink is None or mode not in _RULE_MODES:
                raise audit_errors.InvalidRulesSchemaError(
                    'Faulty rule {}'.format(rule_index))

            for resource in resources:
                resource_type = resource.get('type')
                applies_to = resource.get('applies_to')
                resource_ids = resource.get('resource_ids')
                if resource_type not in self.supported_resource_types:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Invalid resource type in rule {}'.format(rule_index))

                if applies_to not in self.supported_rule_applies_to:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Invalid applies_to type in rule {}'.format(
                            rule_index))

                if applies_to == 'children' and resource_type in [
                        'project', 'billing_account'
                ]:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Rule {} cannot apply to children of a {}'.format(
                            rule_index, resource_type))

                if not resource_ids:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource ids in rule {}'.format(rule_index))

                # For each resource id associated with the rule, create a
                # mapping of applies_to => resource => rules.
                for resource_id in resource_ids:
                    gcp_resource = resource_util.create_resource(
                        resource_id=resource_id, resource_type=resource_type)

                    rule_def_resource = {
                        'sink': sink,
                        'mode': mode,
                    }
                    rule = Rule(rule_name=rule_def.get('name'),
                                rule_index=rule_index,
                                rule=rule_def_resource)

                    # If no mapping exists, create it. If the rule isn't in the
                    # mapping, add it.
                    self.resource_rules_map[applies_to][gcp_resource].add(rule)

        finally:
            self._rules_sema.release()
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Add a rule to the rule book.

        The rule supplied to this method is the dictionary parsed from
        the rules definition file.

        For example, this rule...

        # rules yaml:
            rules:
          - name: all networks covered in whitelist
            project: '*'
            network: '*'
            is_external_network: True
            whitelist:
              master:
                - master-1
              network:
                - network-1
                - network-2
              default:
                - default-1

        ... gets parsed into:
        {
            "rules": [
                {
                    "name": "all networks covered in whitelist",
                    "project": "*",
                    "network": "*",
                    "is_external_network": true,
                    "whitelist": {
                        "master": [
                            "master-1"
                        ],
                        "network": [
                            "network-1",
                            "network-2"
                        ],
                        "default": [
                            "default-1"
                        ]
                    }
                }
            ]
        }

        Args:
            rule_def (dict): A dictionary containing rule definition properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        project = rule_def.get('project')
        network = rule_def.get('network')
        whitelist = rule_def.get('whitelist')
        is_external_network = rule_def.get('is_external_network')

        if ((whitelist is None) or
                (project is None) or
                (network is None) or
                (is_external_network is None)):
            raise audit_errors.InvalidRulesSchemaError(
                'Faulty rule {}'.format(rule_def.get('name')))

        rule_def_resource = {'whitelist': whitelist,
                             'project': escape_and_globify(project),
                             'network': escape_and_globify(network),
                             'is_external_network': is_external_network}

        rule = Rule(rule_name=rule_def.get('name'),
                    rule_index=rule_index,
                    rules=rule_def_resource)

        resource_rules = self.resource_rules_map.get(rule_index)
        if not resource_rules:
            self.resource_rules_map[rule_index] = rule
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        The rule supplied to this method is the dictionary parsed from
        the rules definition file.

        For example, this rule...

            # rules yaml:
            rules:
              - name: a rule
                mode: whitelist
                resource:
                  - type: project
                    applies_to: self
                    resource_ids:
                      - my-project-123
                inherit_from_parents: true
                bindings:
                  - role: roles/editor
                    members:
                      - users:[email protected]

        ... gets parsed into:

            {
                'name': 'a rule',
                'mode': 'whitelist',
                'resource': {
                    'type': 'project',
                    'applies_to': self,
                    'resource_ids': ['my-project-id']
                },
                'inherit_from_parents': true,
                'bindings': [
                    {
                        'role': 'roles/editor',
                        'members': ['users:[email protected]']
                    }
                ]
            }

        Args:
            rule_def (dict): Contains rule definition properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        self._rules_sema.acquire()

        try:
            resources = rule_def.get('resource')

            for resource in resources:
                resource_ids = resource.get('resource_ids')
                resource_type = None
                # TODO: collect these errors and output them in a log.
                # TODO: log the error and keep going
                try:
                    resource_type = resource_mod.ResourceType.verify(
                        resource.get('type'))
                except resource_errors.InvalidResourceTypeError:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource type in rule {}'.format(rule_index))

                if not resource_ids or len(resource_ids) < 1:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource ids in rule {}'.format(rule_index))

                # For each resource id associated with the rule, create a
                # mapping of resource => rules.
                for resource_id in resource_ids:
                    gcp_resource = resource_util.create_resource(
                        resource_id=resource_id, resource_type=resource_type)

                    # TODO: Rewrite this as a list comprehension.
                    # pylint: disable=bad-builtin
                    rule_bindings = filter(None, [
                        iam_policy.IamPolicyBinding.create_from(b)
                        for b in rule_def.get('bindings')
                    ])
                    rule = scanner_rules.Rule(rule_name=rule_def.get('name'),
                                              rule_index=rule_index,
                                              bindings=rule_bindings,
                                              mode=rule_def.get('mode'))

                    rule_applies_to = resource.get('applies_to')
                    rule_key = (gcp_resource, rule_applies_to)

                    # See if we have a mapping of the resource and rule
                    resource_rules = self.resource_rules_map.get(rule_key)

                    # If no mapping exists, create it.
                    if not resource_rules:
                        resource_rules = ResourceRules(
                            resource=gcp_resource,
                            applies_to=rule_applies_to,
                            inherit_from_parents=rule_def.get(
                                'inherit_from_parents', False))
                        self.resource_rules_map[rule_key] = resource_rules

                    # If the rule isn't in the mapping, add it.
                    if rule not in resource_rules.rules:
                        resource_rules.rules.add(rule)
        finally:
            self._rules_sema.release()
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        The rule supplied to this method is the dictionary parsed from
        the rules definition file.

        For example, this rule...

            # rules yaml:
            rules:
              - name: a rule
                mode: whitelist
                resource:
                  - type: project
                    resource_ids:
                      - my-project-123
                services:
                  - 'compute.googleapis.com'
                  - 'storage-component.googleapis.com'
                  - 'storage-api.googleapis.com'

        ... gets parsed into:

            {
                'name': 'a rule',
                'mode': 'whitelist',
                'resource': {
                    'type': 'project',
                    'resource_ids': ['my-project-id']
                },
                'services': [
                    'compute.googleapis.com',
                    'storage-component.googleapis.com',
                    'storage-api.googleapis.com'
                ]
            }

        Args:
            rule_def (dict): Contains rule definition properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        self._rules_sema.acquire()

        try:
            resources = rule_def.get('resource')
            mode = rule_def.get('mode')
            services = rule_def.get('services')
            if not resources or not services or mode not in _RULE_MODES:
                raise audit_errors.InvalidRulesSchemaError(
                    'Faulty rule {}'.format(rule_index))

            for resource in resources:
                resource_ids = resource.get('resource_ids')
                resource_type = resource.get('type')
                if resource_type not in self.supported_resource_types:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Invalid resource type in rule {}'.format(rule_index))

                if not resource_ids or len(resource_ids) < 1:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource ids in rule {}'.format(rule_index))

                # For each resource id associated with the rule, create a
                # mapping of resource => rules.
                for resource_id in resource_ids:
                    if resource_id == '*' and resource_type != 'project':
                        raise audit_errors.InvalidRulesSchemaError(
                            'Wild-card must use project type in rule {}'.
                            format(rule_index))
                    gcp_resource = resource_util.create_resource(
                        resource_id=resource_id, resource_type=resource_type)

                    rule_def_resource = {
                        'services': services,
                        'mode': mode,
                    }
                    rule = Rule(rule_name=rule_def.get('name'),
                                rule_index=rule_index,
                                rule=rule_def_resource)

                    # If no mapping exists, create it. If the rule isn't in the
                    # mapping, add it.
                    self.resource_rules_map[gcp_resource].add(rule)

        finally:
            self._rules_sema.release()