def test_binding_create_from_is_correct(self):
        """Test that the IamPolicyBinding create is correct."""
        # test role, members, role name pattern
        binding = {'role': 'roles/viewer', 'members': self.test_members}
        iam_binding = IamPolicyBinding.create_from(binding)
        self.assertEqual(binding['role'], iam_binding.role_name)
        self.assertEqual(binding['members'],
                         _get_member_list(iam_binding.members))
        self.assertEqual('^roles\/viewer$', iam_binding.role_pattern.pattern)

        # test roles glob
        binding2 = {'role': 'roles/*', 'members': self.test_members}
        iam_binding2 = IamPolicyBinding.create_from(binding2)
        self.assertEqual('^roles\/.+?$', iam_binding2.role_pattern.pattern)
예제 #2
0
    def test_add_single_rule_builds_correct_map(self):
        """Test that adding a single rule builds the correct map."""
        rule_book = ire.IamRuleBook(test_rules.RULES1, self.fake_timestamp)
        actual_rules = rule_book.resource_rules_map

        # expected
        rule_bindings = [{
            'role': 'roles/*',
            'members': ['user:*@company.com']
        }]
        rule = scanner_rules.Rule(
            'my rule',
            0, [IamPolicyBinding.create_from(b) for b in rule_bindings],
            mode='whitelist')
        expected_org_rules = ire.ResourceRules(self.org789,
                                               rules=set([rule]),
                                               applies_to='self_and_children')
        expected_proj1_rules = ire.ResourceRules(self.project1,
                                                 rules=set([rule]),
                                                 applies_to='self')
        expected_proj2_rules = ire.ResourceRules(self.project2,
                                                 rules=set([rule]),
                                                 applies_to='self')
        expected_rules = {
            (self.org789, 'self_and_children'): expected_org_rules,
            (self.project1, 'self'): expected_proj1_rules,
            (self.project2, 'self'): expected_proj2_rules
        }

        self.assertEqual(expected_rules, actual_rules)
예제 #3
0
    def test_one_member_mismatch(self):
        """Test a policy where one member mismatches the whitelist.

        Setup:
            * Create a RulesEngine and add test_rules.RULES1.
            * Create the policy binding.
            * Create the Rule and rule bindings.
            * Create the resource association for the Rule.

        Expected results:
            One policy binding member missing from the whitelist.
        """
        # actual
        rules_local_path = get_datafile_path(__file__, 'test_rules_1.yaml')
        rules_engine = ire.IamRulesEngine(rules_local_path)
        rules_engine.rule_book = ire.IamRuleBook(test_rules.RULES1,
                                                 self.fake_timestamp)
        rules_engine.rule_book.org_res_rel_dao = mock.MagicMock()
        find_ancestor_mock = mock.MagicMock(side_effect=[[self.org789]])
        rules_engine.rule_book.org_res_rel_dao.find_ancestors = \
            find_ancestor_mock

        policy = {
            'bindings': [{
                'role':
                'roles/editor',
                'members': ['user:[email protected]', 'user:[email protected]']
            }]
        }

        actual_violations = set(
            rules_engine.find_policy_violations(self.project1, policy))

        # expected
        rule_bindings = [{
            'role': 'roles/*',
            'members': ['user:*@company.com']
        }]
        rule = scanner_rules.Rule(
            'my rule',
            0, [IamPolicyBinding.create_from(b) for b in rule_bindings],
            mode='whitelist')
        expected_outstanding = {
            'roles/editor':
            [IamPolicyMember.create_from('user:[email protected]')]
        }
        expected_violations = set([
            scanner_rules.RuleViolation(
                resource_type=self.project1.type,
                resource_id=self.project1.id,
                rule_name=rule.rule_name,
                rule_index=rule.rule_index,
                role='roles/editor',
                violation_type=scanner_rules.VIOLATION_TYPE.get(rule.mode),
                members=tuple(expected_outstanding['roles/editor']))
        ])

        self.assertEqual(expected_violations, actual_violations)
예제 #4
0
    def _get_bindings(self, bindings):
        """Get a list of this Rule's bindings as IamPolicyBindings.

        Args:
            bindings: A list of bindings (dict).

        Returns:
            A list of IamPolicyBindings.
        """
        return [IamPolicyBinding.create_from(b) for b in bindings]
예제 #5
0
    def test_policy_binding_matches_whitelist_rules(self):
        """Test that a policy binding matches the whitelist rules.

        Setup:
            * Create a test policy binding.
            * Create a test rule binding.
            * Create a whitelist rule with the test rules.

        Expected results:
            All policy binding members are in the whitelist.
        """
        test_binding = {
            'role':
            'roles/owner',
            'members': [
                'user:[email protected]',
                'user:[email protected]',
                'group:[email protected]',
                'serviceAccount:[email protected]',
            ]
        }
        rule_bindings = [{
            'role':
            'roles/owner',
            'members': [
                'user:*@company.com',
                'user:abc@*.somewhere.com',
                'group:*@googlegroups.com',
                'serviceAccount:*@*.gserviceaccount.com',
            ]
        }]

        rule = scanner_rules.Rule(
            'test rule',
            0, [IamPolicyBinding.create_from(b) for b in rule_bindings],
            mode='whitelist')
        resource_rule = ire.ResourceRules(rules=[rule])
        results = list(
            resource_rule.find_mismatches(self.project1, test_binding))

        self.assertEqual(0, len(results))
예제 #6
0
    def test_policy_binding_mismatches_required_rules(self):
        """Test that a required list of members mismatches policy binding.

        Setup:
            * Create a test policy binding.
            * Create a test rule binding.
            * Create a required rule with the test rules.

        Expected results:
            All required members are found in the policy.
        """
        test_binding = {
            'role':
            'roles/owner',
            'members': [
                'user:[email protected]',
                'group:[email protected]',
                'serviceAccount:[email protected]',
            ]
        }
        rule_bindings = [{
            'role':
            'roles/owner',
            'members': [
                'user:[email protected]',
                'user:[email protected]',
            ]
        }]

        rule = scanner_rules.Rule(
            'test rule',
            0, [IamPolicyBinding.create_from(b) for b in rule_bindings],
            mode='required')
        resource_rule = ire.ResourceRules(resource=self.project1)
        resource_rule.rules.add(rule)
        results = list(
            resource_rule.find_mismatches(self.project1, test_binding))

        self.assertEqual(1, len(results))
예제 #7
0
    def test_policy_binding_does_not_match_blacklist_rules(self):
        """Test that a policy binding does not match the blacklist.

        Setup:
            * Create a test policy binding.
            * Create a test rule binding.
            * Create a blacklist rule with the test rules.

        Expected results:
            No policy bindings found in the blacklist.
        """
        test_binding = {
            'role': 'roles/owner',
            'members': [
                'user:[email protected]',
            ]
        }
        rule_bindings = [{
            'role':
            'roles/owner',
            'members': [
                'user:*@company.com',
                'user:abc@*.somewhere.com',
                'group:*@googlegroups.com',
                'serviceAccount:*@*.gserviceaccount.com',
            ]
        }]

        rule = scanner_rules.Rule(
            'test rule',
            0, [IamPolicyBinding.create_from(b) for b in rule_bindings],
            mode='blacklist')
        resource_rule = ire.ResourceRules(rules=[rule])
        results = list(
            resource_rule.find_mismatches(self.project1, test_binding))

        self.assertEqual(0, len(results))
예제 #8
0
    def find_mismatches(self, policy_resource, binding_to_match):
        """Determine if the policy binding matches this rule's criteria.

        How the member matching operates:

        1. Whitelist: policy members match at least one rule member
        2. Blacklist: policy members must not match any rule members
        3. Require: rule members must all match policy members

        Args:
            policy_resource: The resource that the policy belongs to.
            binding_to_match: The IamPolicyBinding binding to compare to
                this rule's bindings.

        Returns:
            A generator of RuleViolations.
        """
        policy_binding = IamPolicyBinding.create_from(binding_to_match)

        for rule in self.rules:
            # TODO: transform the policy binding into a {role: members} dict
            found_role = False
            for binding in rule.bindings:
                policy_role_name = policy_binding.role_name
                if not policy_binding.role_name.startswith('roles'):
                    policy_role_name = 'roles/{}'.format(
                        policy_binding.role_name)

                # If the rule's role pattern matches the policy binding's role
                # pattern, then check the members to see whether they match,
                # according to the rule mode.
                if binding.role_pattern.match(policy_role_name):
                    if rule.mode == RuleMode.REQUIRED:
                        role_name = binding.role_name
                    else:
                        role_name = policy_role_name
                    found_role = True
                    violating_members = (self._dispatch_rule_mode_check(
                        mode=rule.mode,
                        rule_members=binding.members,
                        policy_members=policy_binding.members))
                    if violating_members:
                        yield RuleViolation(
                            resource_type=policy_resource.resource_type,
                            resource_id=policy_resource.resource_id,
                            rule_name=rule.rule_name,
                            rule_index=rule.rule_index,
                            violation_type=RULE_VIOLATION_TYPE.get(
                                rule.mode, RULE_VIOLATION_TYPE['UNSPECIFIED']),
                            role=role_name,
                            members=violating_members)

            # Extra check if the role did not match in the REQUIRED case.
            if not found_role and rule.mode == RuleMode.REQUIRED:
                for binding in rule.bindings:
                    yield RuleViolation(
                        resource_type=policy_resource.resource_type,
                        resource_id=policy_resource.resource_id,
                        rule_name=rule.rule_name,
                        rule_index=rule.rule_index,
                        violation_type=RULE_VIOLATION_TYPE.get(
                            rule.mode, RULE_VIOLATION_TYPE['UNSPECIFIED']),
                        role=binding.role_name,
                        members=binding.members)
예제 #9
0
 def test_binding_missing_members_raises(self):
     """Test that a binding with no members raises an exception."""
     with self.assertRaises(InvalidIamPolicyBindingError):
         IamPolicyBinding('roles/fake', [])
예제 #10
0
 def test_binding_missing_role_raises(self):
     """Test that a binding with no role raises an exception."""
     with self.assertRaises(InvalidIamPolicyBindingError):
         IamPolicyBinding(None, ['*'])