def test_build_rule_book_no_resource_type_fails(self): """Test that a rule without a resource cannot be created.""" rules_local_path = get_datafile_path(__file__, 'buckets_test_rules_2.yaml') rules_engine = bre.BucketsRulesEngine(rules_file_path=rules_local_path) with self.assertRaises(InvalidRulesSchemaError): rules_engine.build_rule_book()
def test_find_required_violation(self): """Test required api rules.""" rules_local_path = get_datafile_path(__file__, 'enabled_apis_test_rules_2.yaml') rules_engine = eare.EnabledApisRulesEngine( rules_file_path=rules_local_path) rules_engine.build_rule_book() self.assertEqual(2, len(rules_engine.rule_book.resource_rules_map)) # Required API is included. violations = rules_engine.find_violations( self.proj_3, ['foo.googleapis.com', 'bar.googleapis.com']) self.assertEquals(0, len(list(violations))) # Required API is missing. violations = list( rules_engine.find_violations(self.proj_3, ['foo.googleapis.com'])) self.assertEquals(1, len(violations)) self.assertEquals(eare.VIOLATION_TYPE, violations[0].violation_type) self.assertEquals(('bar.googleapis.com', ), violations[0].apis) # Required rule doesn't apply to project. violations = rules_engine.find_violations(self.proj_2, ['foo.googleapis.com']) self.assertEquals(0, len(list(violations)))
def test_find_violation_for_publicly_exposed_acls(self): rules_local_path = get_datafile_path(__file__, 'buckets_test_rules_1.yaml') rules_engine = bre.BucketsRulesEngine(rules_file_path=rules_local_path) rules_engine.build_rule_book() rules_map = rules_engine.rule_book.resource_rules_map all_users_rule = rules_map[0] all_authenticated_users_rule = rules_map[1] # Everything is allowed. acl_dict = json.loads( BUCKET_ACL_TEMPLATE.format(entity='project-owners-123456')) acl = bucket_access_controls.BucketAccessControls.from_dict( 'test-project', 'fake_inventory_data', acl_dict) violation = all_users_rule.find_violations(acl) self.assertEquals(0, len(list(violation))) # Exposed to everyone in the world. acl_dict = json.loads(BUCKET_ACL_TEMPLATE.format(entity='allUsers')) acl = bucket_access_controls.BucketAccessControls.from_dict( 'test-project', 'fake_inventory_data', acl_dict) violation = all_users_rule.find_violations(acl) self.assertEquals(1, len(list(violation))) # Exposed to all google-authenticated users in the world. acl_dict = json.loads( BUCKET_ACL_TEMPLATE.format(entity='allAuthenticatedUsers')) acl = bucket_access_controls.BucketAccessControls.from_dict( 'test-project', 'fake_inventory_data', acl_dict) violation = all_authenticated_users_rule.find_violations(acl) self.assertEquals(1, len(list(violation)))
def test_project_with_no_violations(self): """Tests that no violations are produced for a correct project.""" rules_local_path = get_datafile_path( __file__, 'audit_logging_test_valid_rules.yaml') rules_engine = alre.AuditLoggingRulesEngine( rules_file_path=rules_local_path) rules_engine.build_rule_book() # Creates rules for 5 difference resources. self.assertEqual(5, len(rules_engine.rule_book.resource_rules_map)) # proj-1 needs ADMIN_READ for allServices, and all three log types # for compute and cloudsql. service_configs = { 'allServices': { 'ADMIN_READ': set(), 'DATA_READ': set(), }, 'compute.googleapis.com': { 'DATA_WRITE': set(['user:[email protected]']), }, 'cloudsql.googleapis.com': { 'DATA_WRITE': set(), }, 'logging.googleapis.com': { 'DATA_READ': set(['user:[email protected]']), } } actual_violations = rules_engine.find_violations( self.proj_1, IamAuditConfig(service_configs)) self.assertEqual(set(), actual_violations)
def test_find_whitelist_violation(self): """Test whitelist rules.""" rules_local_path = get_datafile_path(__file__, 'enabled_apis_test_rules_1.yaml') rules_engine = eare.EnabledApisRulesEngine( rules_file_path=rules_local_path) rules_engine.build_rule_book() self.assertEqual(4, len(rules_engine.rule_book.resource_rules_map)) # Everything is allowed. violations = rules_engine.find_violations( self.proj_3, ['foo.googleapis.com', 'bar.googleapis.com', 'baz.googleapis.com']) self.assertEquals(0, len(list(violations))) # Non-whitelisted APIs. violations = list( rules_engine.find_violations(self.proj_3, [ 'alpha.googleapis.com', 'bar.googleapis.com', 'other-api.com' ])) self.assertEquals(1, len(violations)) self.assertEquals(eare.VIOLATION_TYPE, violations[0].violation_type) self.assertEquals(('alpha.googleapis.com', 'other-api.com'), violations[0].apis) # API is whitelisted for Organization, but not globally (wildcard). violations = list( rules_engine.find_violations(self.proj_1, ['qux.googleapis.com'])) self.assertEquals(1, len(violations)) self.assertEquals(eare.VIOLATION_TYPE, violations[0].violation_type) self.assertEquals(('qux.googleapis.com', ), violations[0].apis)
def setUp(self): self.scanner = ke_scanner.KeScanner({}, {}, self.service_config, self.model_name, '', unittest_utils.get_datafile_path( __file__, 'ke_scanner_test_data.yaml'))
def test_build_rule_book_from_local_yaml_file_works(self): """Test that a RuleBook is built correctly with a yaml file.""" rules_local_path = get_datafile_path(__file__, 'buckets_test_rules_1.yaml') rules_engine = bre.BucketsRulesEngine(rules_file_path=rules_local_path) rules_engine.build_rule_book() self.assertEqual(2, len(rules_engine.rule_book.resource_rules_map))
def test_empty_policy_with_rules_no_violations(self): """Test an empty policy against the RulesEngine with rules. Setup: * Create a RulesEngine. * Created expected violations list. Expected results: No policy violations found. """ # 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 actual_violations = set( rules_engine.find_policy_violations(self.project1, {})) # expected expected_violations = set() self.assertEqual(expected_violations, actual_violations)
def test_org_whitelist_rules_vs_policy_no_violations(self): """Test ruleset on an org with whitelist with no rule violations. Setup: * Create a RulesEngine with RULES1 rule set. * Create policy. Expected result: * Find no rule violations. """ # actual rules_local_path = get_datafile_path(__file__, 'test_rules_1.yaml') rules_engine = OrgRulesEngine(rules_local_path) rules_engine.rule_book = OrgRuleBook(self.RULES1) policy = { 'bindings': [{ 'role': 'roles/editor', 'members': [ 'user:[email protected]', ] }] } actual_violations = [] actual_violations.extend( rules_engine.find_policy_violations(self.org789, policy)) self.assertItemsEqual([], actual_violations)
def test_build_rule_book_no_protocol_fails(self): """Test that a rule without a protocol cannot be created.""" rules_local_path = get_datafile_path(__file__, 'fwd_test_rules_2.yaml') rules_engine = fre.ForwardingRuleRulesEngine( rules_file_path=rules_local_path) with self.assertRaises(InvalidRulesSchemaError): rules_engine.build_rule_book()
def test_org_whitelist_rules_vs_policy_no_violations(self): """Test ruleset on an org with whitelist with no rule violations. Setup: * Create a RulesEngine with RULES1 rule set. * Create policy. Expected result: * Find no rule violations. """ # 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=[[]]) rules_engine.rule_book.org_res_rel_dao.find_ancestors = \ find_ancestor_mock policy = { 'bindings': [{ 'role': 'roles/editor', 'members': [ 'user:[email protected]', ] }] } actual_violations = set( rules_engine.find_policy_violations(self.org789, policy)) self.assertItemsEqual(set(), actual_violations)
def test_find_violations_inapplicable_resource(self): # rules are set on org 234 org = organization.Organization( '000', display_name='Organization 000', full_name='organization/000/', data='fake_org_data_000', ) proj = project.Project( '111', project_number=111, display_name='My project 111', parent=org, full_name='organization/000/project/111/', data='fake_project_data_111', ) rules_local_path = get_datafile_path(__file__, 'bigquery_test_rules_4.yaml') rules_engine = bqe.BigqueryRulesEngine(rules_local_path) rules_engine.build_rule_book() fake_bq_acls = create_list_of_bq_objects_from_data() actual_violations_list = [] for bqt in fake_bq_acls: violation = rules_engine.find_violations(proj, bqt) actual_violations_list.extend(violation) self.assertEqual([], actual_violations_list)
def test_build_rule_book_from_gcs_works(self, mock_load_rules_from_gcs): """Test that a RuleBook is built correctly with a mocked gcs file. Setup: * Create a mocked GCS object from a test yaml file. * Get the yaml file content. Expected results: There are 4 resources that have rules, in the rule book. """ bucket_name = 'bucket-name' rules_path = 'input/bigquery_test_rules_1.yaml' full_rules_path = 'gs://{}/{}'.format(bucket_name, rules_path) rules_engine = bqe.BigqueryRulesEngine(rules_file_path=full_rules_path) # Read in the rules file file_content = None with open(get_datafile_path(__file__, 'bigquery_test_rules_1.yaml'), 'r') as rules_local_file: try: file_content = yaml.safe_load(rules_local_file) except yaml.YAMLError: raise mock_load_rules_from_gcs.return_value = file_content rules_engine.build_rule_book() self.assertEqual(1, len(rules_engine.rule_book.resource_rules_map))
def test_org_project_inherit_org_rule_violation(self): """Test org with blacklist and child with whitelist, no inherit. Test that the project whitelist rule overrides the org blacklist rule when the project does not inherit from parent. Setup: * Create a RulesEngine with RULES5 rule set. * Create policy. Expected result: * Find 1 rule violation. """ # actual rules_local_path = get_datafile_path(__file__, 'test_rules_1.yaml') rules_engine = ire.IamRulesEngine(rules_local_path) rules5 = copy.deepcopy(test_rules.RULES5) rules5['rules'][1]['inherit_from_parents'] = True rules_engine.rule_book = ire.IamRuleBook(rules5, 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 project_policy = { 'bindings': [ { 'role': 'roles/owner', 'members': [ 'user:[email protected]', ] } ] } actual_violations = set( rules_engine.find_policy_violations(self.project1, project_policy) ) # expected expected_outstanding_proj = { 'roles/owner': [ IamPolicyMember.create_from('user:[email protected]') ] } expected_violations = set([ scanner_rules.RuleViolation( rule_index=0, rule_name='org blacklist', resource_id=self.project1.id, resource_type=self.project1.type, violation_type='ADDED', role=project_policy['bindings'][0]['role'], members=tuple(expected_outstanding_proj['roles/owner'])), ]) self.assertItemsEqual(expected_violations, actual_violations)
def test_build_rule_book_invalid_mode_fails(self): """Test that a rule with an inavlid mode cannot be created.""" rules_local_path = get_datafile_path(__file__, 'enabled_apis_test_rules_3.yaml') rules_engine = eare.EnabledApisRulesEngine( rules_file_path=rules_local_path) with self.assertRaises(InvalidRulesSchemaError): rules_engine.build_rule_book()
def get_engine_with_valid_rules(self): """Create a rule engine build with a valid rules file.""" rules_local_path = get_datafile_path(__file__, 'log_sink_test_valid_rules.yaml') rules_engine = self.lsre.LogSinkRulesEngine( rules_file_path=rules_local_path) rules_engine.build_rule_book() return rules_engine
def test_build_rule_book_invalid_mode_fails(self): """Tests that a rule with an inavlid mode cannot be created.""" rules_local_path = get_datafile_path( __file__, 'audit_logging_test_invalid_rules.yaml') rules_engine = alre.AuditLoggingRulesEngine( rules_file_path=rules_local_path) with self.assertRaises(InvalidRulesSchemaError): rules_engine.build_rule_book()
def test_build_rule_book_invalid_applies_to_fails(self): """Tests that a rule with invalid applies_to type cannot be created.""" rules_local_path = get_datafile_path( __file__, 'log_sink_test_invalid_rules.yaml') rules_engine = self.lsre.LogSinkRulesEngine( rules_file_path=rules_local_path) with self.assertRaises(InvalidRulesSchemaError): rules_engine.build_rule_book()
def test_yaml_file_bad_ancestor(self): """Test that a RuleBook is built correctly with a yaml file.""" rules_local_path = get_datafile_path( __file__, 'external_project_access_test_rules_2.yaml') rules_engine = engine_module.ExternalProjectAccessRulesEngine( rules_file_path=rules_local_path) with self.assertRaises(audit_errors.InvalidRulesSchemaError): rules_engine.build_rule_book(self.inventory_config)
def test_good_yaml_file(self): """Test that a RuleBook is built correctly with a yaml file.""" rules_local_path = get_datafile_path( __file__, 'external_project_access_test_rules_1.yaml') rules_engine = engine_module.ExternalProjectAccessRulesEngine( rules_file_path=rules_local_path) rules_engine.build_rule_book(self.inventory_config) self.assertEqual(2, len(rules_engine.rule_book.resource_rules_map))
def test_org_2_child_rules_report_violation(self): """Test org "children" whitelist works with org "children" blacklist. Test that org children whitelist with org children blacklist rules report violation. Setup: * Create a RulesEngine with RULES6 rule set. * Create policy. Expected result: * Find 1 rule violation. """ # 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.RULES6, 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 project_policy = { 'bindings': [ { 'role': 'roles/owner', 'members': [ 'user:[email protected]', ] } ] } actual_violations = set( rules_engine.find_policy_violations(self.project1, project_policy) ) # expected expected_outstanding_proj = { 'roles/owner': [ IamPolicyMember.create_from('user:[email protected]') ] } expected_violations = set([ scanner_rules.RuleViolation( rule_index=1, rule_name='project blacklist', resource_id=self.project1.id, resource_type=self.project1.type, violation_type='ADDED', role=project_policy['bindings'][0]['role'], members=tuple(expected_outstanding_proj['roles/owner'])), ]) self.assertItemsEqual(expected_violations, actual_violations)
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)
def test_build_rule_book_from_local_yaml_file_works(self): """Test that a RuleBook is built correctly with a yaml file.""" rules_local_path = get_datafile_path( __file__, 'instance_network_interface_test_rules_1.yaml') rules_engine = ini.InstanceNetworkInterfaceRulesEngine( rules_file_path=rules_local_path) rules_engine.build_rule_book() self.assertEqual(1, len(rules_engine.rule_book.resource_rules_map))
def test_build_rule_book_from_local_yaml_file_works(self): """Test that a RuleBook is built correctly with a yaml file.""" rules_local_path = get_datafile_path(__file__, 'enabled_apis_test_rules_1.yaml') rules_engine = eare.EnabledApisRulesEngine( rules_file_path=rules_local_path) rules_engine.build_rule_book() # Creates rules for 4 difference resources. self.assertEqual(4, len(rules_engine.rule_book.resource_rules_map))
def test_build_rule_book_overlapping_resources_works(self): """Test a RuleBook with multiple rules on a single resource.""" rules_local_path = get_datafile_path(__file__, 'enabled_apis_test_rules_2.yaml') rules_engine = eare.EnabledApisRulesEngine( rules_file_path=rules_local_path) rules_engine.build_rule_book() # Creates rules for 2 difference resources. self.assertEqual(2, len(rules_engine.rule_book.resource_rules_map))
def setUp(self, mock_rules_engine): mre = mock.patch( 'google.cloud.forseti.scanner.scanners.firewall_rules_scanner.' 'firewall_rules_engine').start() self.fake_utcnow = datetime(year=1900, month=1, day=1, hour=0, minute=0, second=0, microsecond=0) self.fake_scanner_configs = {'output_path': '/fake/output/path'} rules_local_path = unittest_utils.get_datafile_path( os.path.join(os.path.dirname(__file__), 'audit'), 'firewall_test_rules.yaml') self.scanner = firewall_rules_scanner.FirewallPolicyScanner( {}, {}, mock.MagicMock(), '', '', rules_local_path) self.mock_rules_engine = mre self.project0 = fre.resource_util.create_resource( resource_id='test_project', resource_type='project') self.project1 = fre.resource_util.create_resource( resource_id='project1', resource_type='project') self.project2 = fre.resource_util.create_resource( resource_id='project2', resource_type='project') self.project3 = fre.resource_util.create_resource( resource_id='project3', resource_type='project') self.exception = fre.resource_util.create_resource( resource_id='honeypot_exception', resource_type='project') self.folder1 = fre.resource_util.create_resource( resource_id='folder1', resource_type='folder') self.folder2 = fre.resource_util.create_resource( resource_id='test_instances', resource_type='folder') self.folder3 = fre.resource_util.create_resource( resource_id='folder3', resource_type='folder') self.folder4 = fre.resource_util.create_resource( resource_id='folder4', resource_type='folder') self.org = fre.resource_util.create_resource( resource_id='org', resource_type='organization') self.project4 = fre.resource_util.create_resource( resource_id='test_project_2', resource_type='project') self.project_resource_map = { 'test_project': self.project0, 'project1': self.project1, 'project2': self.project2, 'project3': self.project3, 'test_project_2': self.project4, 'honeypot_exception': self.exception, } self.ancestry = { self.project0: [self.folder1, self.org], self.project1: [self.folder2, self.org], self.project2: [self.folder4, self.folder3, self.org], self.project3: [self.folder3, self.org], self.project4: [self.folder3, self.org], self.exception: [self.folder3, self.org], }
def test_folder_rule_whitelist(self): """Test a simple folder whitelist rule.""" 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.FOLDER_RULES1, self.fake_timestamp) rules_engine.rule_book.org_res_rel_dao = mock.MagicMock() find_ancestor_mock = mock.MagicMock( side_effect=[[self.org789], [self.folder1, self.org789]]) rules_engine.rule_book.org_res_rel_dao.find_ancestors = \ find_ancestor_mock # one violation for folder because of organization 778899 # one violation for project because of project3's parent folder_policy = { 'bindings': [{ 'role': 'roles/editor', 'members': [ 'user:[email protected]', ] }] } project_policy = { 'bindings': [{ 'role': 'roles/editor', 'members': [ 'user:[email protected]', ] }] } actual_violations = set( itertools.chain( rules_engine.find_policy_violations(self.folder1, folder_policy), rules_engine.find_policy_violations(self.project3, project_policy))) # expected expected_outstanding = { 'roles/editor': [IamPolicyMember.create_from('user:[email protected]')] } expected_violations = set([ scanner_rules.RuleViolation( rule_index=0, rule_name='folder rule 1', resource_id=self.folder1.id, resource_type=self.folder1.type, violation_type='ADDED', role=project_policy['bindings'][0]['role'], members=tuple(expected_outstanding['roles/editor'])), ]) self.assertItemsEqual(expected_violations, actual_violations)
def test_find_violations_unset_acl_field(self): rules_local_path = get_datafile_path(__file__, 'bigquery_test_rules_11.yaml') rules_engine = bqe.BigqueryRulesEngine(rules_local_path) rules_engine.build_rule_book() fake_bq_acls_data = create_list_of_bq_objects_from_data() actual_violations_list = [] for bqt in fake_bq_acls_data: violation = rules_engine.find_violations(self.project, bqt) actual_violations_list.extend(violation) self.assertEqual([], actual_violations_list)
def test_find_violations_blacklist_with_no_violations(self): """Test that a rule for a given rule there are no violations.""" rules_local_path = get_datafile_path(__file__, 'bigquery_test_rules_3.yaml') rules_engine = bqe.BigqueryRulesEngine(rules_local_path) rules_engine.build_rule_book() fake_bq_acls = create_list_of_bq_objects_from_data() actual_violations_list = [] for bqt in fake_bq_acls: violation = rules_engine.find_violations(self.project, bqt) actual_violations_list.extend(violation) self.assertEqual([], actual_violations_list)
def test_run_scanner_rotation_period_whitelist_match( self, mock_output_results): self.scanner = kms_scanner.KMSScanner( {}, {}, self.service_config, self.model_name, '', unittest_utils.get_datafile_path( __file__, 'kms_scanner_whitelist_test.yaml')) self.scanner.run() crypto_key = self.scanner._retrieve() violations = self.scanner._find_violations(crypto_key) self.assertEquals(1, len(violations)) self.assertEquals(1, mock_output_results.call_count)