def test_create_resource_is_ok(self):
        """Test the resource_util.create_resource() creates the types."""
        expect_org = Organization(12345)
        actual_org = resource_util.create_resource(
            12345, ResourceType.ORGANIZATION)
        self.assertEqual(expect_org, actual_org)

        expect_proj = Project('abcd', project_number=54321)
        actual_proj = resource_util.create_resource(
            'abcd', ResourceType.PROJECT, project_number=54321)
        self.assertEqual(expect_proj, actual_proj)
        self.assertEqual(expect_proj.project_number, actual_proj.project_number)
Exemplo n.º 2
0
def find_ancestors(starting_resource, full_name):
    """Find the ancestors for a given resource.

    Take advantage of the full name from the data model which has
    the entire hierarchy.

    Keeping this outside of the class, because the class is mocked out during
    testing.

    Args:
        starting_resource (Resource): The GCP resource associated with the
            policy binding.  This is where we move up the resource
            hierarchy.
        full_name (str): Full name of the resource in hierarchical format.
            Example of a full_name:
            organization/88888/project/myproject/firewall/99999/

    Returns:
        list: A list of GCP resources in ascending order in the resource
        hierarchy.
    """
    ancestor_resources = [starting_resource]

    resources = utils.get_resources_from_full_name(full_name)
    for resource_type, resource_id in resources:
        if (resource_type == starting_resource.type
                and resource_id == starting_resource.id):
            continue
        new_resource = resource_util.create_resource(resource_id,
                                                     resource_type)
        if new_resource:
            ancestor_resources.append(new_resource)

    return ancestor_resources
    def find_violations(self, project, enabled_apis):
        """Find enabled APIs violations in the rule book.

        Args:
            project (gcp_type): The project that these APIs are enabled on.
            enabled_apis (list): list of enabled APIs.

        Returns:
            iterable: A generator of the rule violations.
        """
        violations = itertools.chain()

        # Check for rules on all ancestors, and the wildcard rule.
        resource_ancestors = (relationship.find_ancestors(
            project, project.full_name))
        resource_ancestors.append(
            resource_util.create_resource(resource_id='*',
                                          resource_type='project'))

        for curr_resource in resource_ancestors:
            resource_rules = self.resource_rules_map.get(curr_resource, [])
            for resource_rule in resource_rules:
                violations = itertools.chain(
                    violations,
                    resource_rule.find_violations(project, enabled_apis))

        return violations
Exemplo n.º 4
0
    def find_violations(self, settings, iam_only):
        """Find groups settings violations in the rule book.

        Args:
            settings (GroupsSettings): The GCP resource to check for violations.
            iam_only (bool): IAM only.

        Returns:
            RuleViolation: resource groups settings rule violations.
        """
        LOGGER.debug('Looking for groups settings violations: %s',
                     settings.name)
        violations = []

        resource_rules = self.get_resource_rules(settings)
        if resource_rules:
            violations.extend(
                resource_rules.find_violations(settings, iam_only))

        wildcard_resource = resource_util.create_resource(
            resource_id='*', resource_type=settings.type)

        resource_rules = self.get_resource_rules(wildcard_resource)
        if resource_rules:
            violations.extend(
                resource_rules.find_violations(settings, iam_only))

        LOGGER.debug('Returning violations: %r', violations)
        return violations
    def test_flatten_violations(self):
        """Test flattening violations"""
        epas.get_user_emails = mock.MagicMock(return_value=TEST_EMAILS)
        violation1 = Rule.RuleViolation(
            resource_type=resource_mod.ResourceType.PROJECT,
            resource_id='12345',
            rule_name='Only my org',
            rule_index=0,
            rule_data=dict(ancestor_resources=[
                resource_util.create_resource('45678', 'organization')
            ]),
            full_name='projects/12345',
            violation_type='EXTERNAL_PROJECT_ACCESS_VIOLATION',
            member='*****@*****.**',
            resource_data=['projects/12345', 'organizations/67890'])

        scanner = epas.ExternalProjectAccessScanner(
            self.global_configs, self.scanner_configs, self.service_config,
            self.model_name, self.snapshot_timestamp, self.rules)
        flattened_iter = scanner._flatten_violations([violation1])

        flat_violation = flattened_iter.next()
        self.assertEqual(flat_violation['resource_id'], '12345')
        self.assertEqual(flat_violation['resource_type'],
                         resource_mod.ResourceType.PROJECT)
        self.assertEqual(flat_violation['rule_name'], 'Only my org')
        self.assertEqual(flat_violation['full_name'], 'projects/12345')
        self.assertEqual(flat_violation['violation_data']['member'],
                         '*****@*****.**')

        with self.assertRaises(StopIteration):
            flat_violation = flattened_iter.next()
Exemplo n.º 6
0
    def find_violations(self, parent_resource, liens):
        """Find lien violations in the rule book.

        Args:
            parent_resource (Resource): The GCP resource associated with the
                liens. This is where we start looking for rule violations and
                we move up the resource hierarchy (if permitted by the
                resource's "inherit_from_parents" property).
            liens (List[Lien]): The liens to look for violations.

        Yields:
            RuleViolation: lien rule violations.
        """

        all_restrictions = set()
        for lien in liens:
            for restriction in lien.restrictions:
                all_restrictions.add(restriction)

        resource_ancestors = relationship.find_ancestors(
            parent_resource, parent_resource.full_name)

        applicable_rules = []

        for res in resource_ancestors:
            applicable_rules.extend(self.resource_to_rules.get(res, []))
            wildcard_res = resource_util.create_resource(
                resource_id='*', resource_type=res.type)
            applicable_rules.extend(
                self.resource_to_rules.get(wildcard_res, []))

        for rule in applicable_rules:
            for violation in rule.find_violations(parent_resource,
                                                  all_restrictions):
                yield violation
Exemplo n.º 7
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)
    def find_violations(self, res):
        """Find resource locations violations in the rule book.

        Args:
            res (Resource): The GCP resource to check locations for.
                This is where we start looking for rule violations and
                we move up the resource hierarchy.

        Yields:
            RuleViolation: resource locations rule violations.
        """

        resource_ancestors = relationship.find_ancestors(res, res.full_name)

        rules = []
        for ancestor_res in resource_ancestors:
            rules.extend(self.resource_to_rules.get(ancestor_res, []))

        type_resource_wildcard = resource_util.create_resource(
            resource_id='*', resource_type=res.type)

        rules.extend(self.resource_to_rules.get(type_resource_wildcard, []))

        for rule in rules:
            for violation in rule.find_violations(res):
                yield violation
    def process_rule(self, rule_def, rule_index):
        """Process 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:
            processed_rule: The dict containing the resources and users to
                which the rule applies
        """
        processed_rule = {'ancestor_resources': []}

        allowed_ancestors = rule_def.get('allowed_ancestors', None)
        self.validate_ancestors(allowed_ancestors, rule_index)

        for allowed_ancestor in allowed_ancestors:
            processed_rule['ancestor_resources'].append(
                resource_util.create_resource(
                    allowed_ancestor.split('/')[1],
                    resource_util.type_from_name(allowed_ancestor)))

        users = rule_def.get('users', None)
        if users:
            self.validate_users(users, rule_index)
            processed_rule['users'] = users

        return processed_rule
    def find_violations(self, project, audit_config):
        """Find Cloud Audit Logging violations in the rule book.

        Args:
            project (gcp_type): The project that has this configuation.
            audit_config (IamAuditConfig): The audit config for this project,
                merged with ancestor configs.

        Returns:
            iterable: A generator of the rule violations.
        """
        violations = itertools.chain()

        # Check for rules on all ancestors, and the wildcard rule.
        resource_ancestors = (relationship.find_ancestors(
            project, project.full_name))
        resource_ancestors.append(
            resource_util.create_resource(resource_id='*',
                                          resource_type='project'))

        for curr_resource in resource_ancestors:
            resource_rules = self.resource_rules_map.get(curr_resource, [])
            for resource_rule in resource_rules:
                violations = itertools.chain(
                    violations,
                    resource_rule.find_violations(project, audit_config))

        return violations
    def find_violations(self, resource, policy, policy_bindings):
        """Find policy binding violations in the rule book.

        Args:
            resource (gcp_type): The GCP resource associated with the
                policy binding.
                This is where we start looking for rule violations and
                we move up the resource hierarchy (if permitted by the
                resource's "inherit_from_parents" property).
            policy (forseti_data_model_resource): The policy to compare
                against the rules.
                See https://cloud.google.com/iam/reference/rest/v1/Policy.
            policy_bindings (list): A list of IamPolicyBindings.

        Returns:
            iterable: A generator of the rule violations.
        """
        violations = itertools.chain()

        resource_ancestors = (relationship.find_ancestors(
            resource, policy.full_name))

        for curr_resource in resource_ancestors:
            wildcard_resource = resource_util.create_resource(
                resource_id='*', resource_type=curr_resource.type)
            resource_rules = self._get_resource_rules(curr_resource)
            resource_rules.extend(self._get_resource_rules(wildcard_resource))

            # Set to None, because if the direct resource (e.g. project)
            # doesn't have a specific rule, we still should check the
            # ancestry to see if the resource's parents have any rules
            # that apply to the children.
            inherit_from_parents = None

            for resource_rule in resource_rules:
                if not self._rule_applies_to_resource(resource, curr_resource,
                                                      resource_rule):
                    continue

                violations = itertools.chain(
                    violations,
                    resource_rule.find_mismatches(resource, policy_bindings))

                inherit_from_parents = resource_rule.inherit_from_parents

            # If the rule does not inherit the parents' rules, stop.
            # Due to the way rules are structured, we only define the
            # "inherit" property once per rule. So even though a rule
            # may apply to multiple resources, it will only have one
            # value for "inherit_from_parents".
            if not inherit_from_parents and inherit_from_parents is not None:
                break

        return violations
Exemplo n.º 12
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)
Exemplo n.º 13
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)
Exemplo n.º 14
0
    def add_org_policy(self, org_def):
        """Creates org policy and rule mapping.

        Sample org structure:

                org 1234
               /        \
              f-1       p-c
             /  \
           p-a  p-b

        Rules can be applied at any node above. When a policy is being audited,
        it the rulebook will start at the lowest level (the project) and will
        walk up the hierarchy until it reaches the first instance with rules and
        these are the only rules that are checked.

        Args:
          org_def (dict): A dictionary of resource ids and enforced rules.

        Raises:
          RuleDoesntExistError: Raised if a rule included in the group does not
            exist.
          GroupDoesntExistError: Raised if a group included in an org policy
            does not exist.
          InvalidOrgDefinition: Raised if org policy doesn't have resources.
        """
        resources = org_def.get('resources', [])
        if not resources:
            raise InvalidOrgDefinition(
                'Org policy does not have any resources')
        for resource in resources:
            resource_type = resource_mod.ResourceType.verify(
                resource.get('type'))
            ids = resource.get('resource_ids', [])
            rules = resource.get('rules', {})
            groups = rules.get('group_ids', [])
            expanded_rules = set()
            for group_id in groups:
                if group_id not in self.rule_groups_map:
                    raise GroupDoesntExistError('Group "%s" does not exist' %
                                                group_id)
                expanded_group = self.rule_groups_map.get(group_id, [])
                expanded_rules.update(expanded_group)
            for rule_id in rules.get('rule_ids', []):
                if rule_id not in self.rules_map:
                    raise RuleDoesntExistError('Rule id "%s" does not exist' %
                                               rule_id)
                expanded_rules.add(rule_id)
            for resource_id in ids:
                gcp_resource = resource_util.create_resource(
                    resource_id=resource_id, resource_type=resource_type)
                self.org_policy_rules_map[gcp_resource] = sorted(
                    expanded_rules)
    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)
Exemplo n.º 16
0
    def test_create_from_resource_utils(self):
        """Tests creating a Billing Account using resource_util."""
        billing_acct = resource_util.create_resource(
            resource_id='000000-111111-222222',
            resource_type='billing_account',
            full_name='organization/234/billing_account/000000-111111-222222/',
            parent=self.org_234)

        self.assertEqual('000000-111111-222222', billing_acct.id)
        self.assertEqual('billing_account', billing_acct.type)
        self.assertEqual('billingAccounts/000000-111111-222222',
                         billing_acct.name)
        self.assertEqual(
            'organization/234/billing_account/000000-111111-222222/',
            billing_acct.full_name)
Exemplo n.º 17
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.
        """
        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)
    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)
Exemplo n.º 20
0
    def _find_violations(self, policies):
        """Find violations in the policies.

        Args:
            policies (list): The list of policies to find violations in.

        Returns:
            list: A list of all violations
        """
        all_violations = []
        LOGGER.info('Finding firewall policy violations...')
        for resource_id, p_policies in policies.items():
            resource = resource_util.create_resource(resource_id=resource_id,
                                                     resource_type='project')
            LOGGER.debug('%s => %s', resource, p_policies)
            violations = self.rules_engine.find_violations(
                resource, p_policies)
            all_violations.extend(violations)
        return all_violations
Exemplo n.º 21
0
    def find_violations(self, ke_cluster):
        """Find violations in the rule book.

        Args:
            ke_cluster (KeCluster): KE Cluster and ServerConfig data.

        Returns:
            list: RuleViolation
        """
        LOGGER.debug('Looking for KE violations: %r', ke_cluster)
        violations = []
        resource_ancestors = resource_util.get_ancestors_from_full_name(
            ke_cluster.full_name)

        LOGGER.debug('Ancestors of resource: %r', resource_ancestors)

        checked_wildcards = set()
        for curr_resource in resource_ancestors:
            if not curr_resource:
                # resource_ancestors will contain all the resources including
                # the child resource, which has type kebernete cluster and
                # cannot be created (return None) as part of the ancestor path,
                # we will skip the child as it's not part of the ancestor.
                continue

            resource_rule = self.get_resource_rules(curr_resource)
            if resource_rule:
                violations.extend(
                    resource_rule.find_violations(ke_cluster))

            wildcard_resource = resource_util.create_resource(
                resource_id='*', resource_type=curr_resource.type)
            if wildcard_resource in checked_wildcards:
                continue
            checked_wildcards.add(wildcard_resource)
            resource_rule = self.get_resource_rules(wildcard_resource)
            if resource_rule:
                violations.extend(
                    resource_rule.find_violations(ke_cluster))

        LOGGER.debug('Returning violations: %r', violations)
        return violations
Exemplo n.º 22
0
    def _retrieve(self):
        """Retrieves the data for scanner.

        Returns:
            list: a list of custom Roles, no curated roles.
        """
        model_manager = self.service_config.model_manager
        scoped_session, data_access = model_manager.get(self.model_name)
        role_res = []
        with scoped_session as session:
            for resource in data_access.scanner_iter(session, 'role'):
                parent = resource_util.create_resource(
                    resource_id=resource.parent.name,
                    resource_type=resource.parent.type)
                parent.full_name = resource.parent.full_name
                new_res = resource_util.create_resource_from_json(
                    'role', parent, resource.data)
                role_res.append(new_res)

        return role_res
Exemplo n.º 23
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 find_violations(self, service_account):
        """Find violations in the rule book.

        Args:
            service_account (ServiceAccount): service account resource.

        Returns:
            list: RuleViolation
        """
        LOGGER.debug('Looking for service account key violations: %s',
                     service_account.full_name)
        violations = []
        resource_ancestors = resource_util.get_ancestors_from_full_name(
            service_account.full_name)

        LOGGER.debug('Ancestors of resource: %r', resource_ancestors)

        checked_wildcards = set()
        for curr_resource in resource_ancestors:
            if not curr_resource:
                # The leaf node in the hierarchy
                continue

            resource_rule = self.get_resource_rules(curr_resource)
            if resource_rule:
                violations.extend(
                    resource_rule.find_violations(service_account))

            wildcard_resource = resource_util.create_resource(
                resource_id='*', resource_type=curr_resource.type)
            if wildcard_resource in checked_wildcards:
                continue
            checked_wildcards.add(wildcard_resource)
            resource_rule = self.get_resource_rules(wildcard_resource)
            if resource_rule:
                violations.extend(
                    resource_rule.find_violations(service_account))

        LOGGER.debug('Returning violations: %r', violations)
        return violations
    def find_violations(self, key):
        """Find crypto key violations in the rule book.

        Args:
            key (CryptoKey): The GCP resource to check for violations.

        Returns:
            RuleViolation: resource crypto key rule violations.
        """
        LOGGER.debug('Looking for crypto key violations: %s',
                     key.name)
        violations = []
        resource_ancestors = resource_util.get_ancestors_from_full_name(
            key.crypto_key_full_name)

        LOGGER.debug('Ancestors of resource: %r', resource_ancestors)

        checked_wildcards = set()
        for curr_resource in resource_ancestors:
            if not curr_resource:
                # The leaf node in the hierarchy
                continue

            resource_rule = self.get_resource_rules(curr_resource)
            if resource_rule:
                violations.extend(
                    resource_rule.find_violations(key))

            wildcard_resource = resource_util.create_resource(
                resource_id='*', resource_type=curr_resource.type)
            if wildcard_resource in checked_wildcards:
                continue
            checked_wildcards.add(wildcard_resource)
            resource_rule = self.get_resource_rules(wildcard_resource)
            if resource_rule:
                violations.extend(
                    resource_rule.find_violations(key))

        LOGGER.debug('Returning violations: %r', violations)
        return violations
Exemplo n.º 26
0
    def _retrieve(self):
        """Retrieves the data for scanner.

        Returns:
            list: a list of Resources, with a type in
                SUPPORTED_RETENTION_RES_TYPES
        """
        model_manager = self.service_config.model_manager
        scoped_session, data_access = model_manager.get(self.model_name)
        retention_res = []
        with scoped_session as session:
            for resource_type in rre.SUPPORTED_RETENTION_RES_TYPES:
                for resource in data_access.scanner_iter(
                        session, resource_type):
                    parent = resource_util.create_resource(
                        resource_id=resource.parent.name,
                        resource_type=resource.parent.type)
                    parent.full_name = resource.parent.full_name
                    new_res = resource_util.create_resource_from_json(
                        resource_type, parent, resource.data)
                    retention_res.append(new_res)

        return retention_res
    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()
    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()
 def test_create_nonexist_resource_returns_None(self):
     """Test that nonexistent resource type creates None."""
     self.assertIsNone(
         resource_util.create_resource('fake-id', 'nonexist'))