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_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/test_rules_1.yaml' full_rules_path = 'gs://{}/{}'.format(bucket_name, rules_path) rules_engine = OrgRulesEngine(rules_file_path=full_rules_path) # Read in the rules file file_content = None with open(get_datafile_path(__file__, '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(4, len(rules_engine.rule_book.resource_rules_map))
def main(_): """Run the scanner.""" logger = LogUtil.setup_logging(__name__) file_path = FLAGS.rules output_path = FLAGS.output_path logger.info(('Initializing the rules engine: ' '\n rules: {}').format(file_path)) rules_engine = OrgRulesEngine(rules_file_path=file_path) rules_engine.build_rule_book() snapshot_timestamp = _get_timestamp(logger) if not snapshot_timestamp: logger.info('No snapshot timestamp found. Exiting.') sys.exit() org_policies = _get_org_policies(logger, snapshot_timestamp) project_policies = _get_project_policies(logger, snapshot_timestamp) if not org_policies and not project_policies: logger.info('No policies found. Exiting.') sys.exit() all_violations = _find_violations( logger, itertools.chain(org_policies.iteritems(), project_policies.iteritems()), rules_engine) csv_name = csv_writer.write_csv(resource_name='policy_violations', data=_write_violations_output( logger, all_violations), write_header=True) logger.info('CSV filename: {}'.format(csv_name)) # scanner timestamp for output file and email now_utc = datetime.utcnow() output_filename = _get_output_filename(now_utc) if output_path: _upload_csv_to_gcs(logger, output_path, output_filename, csv_name) if all_violations: _send_email( csv_name, now_utc, all_violations, { ResourceType.ORGANIZATION: len(org_policies.keys()), ResourceType.PROJECT: len(project_policies.keys()) }) logger.info('Done!')
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 = OrgRulesEngine(rules_local_path) rules_engine.rule_book = OrgRuleBook(self.RULES1) actual_violations = rules_engine.find_policy_violations( self.project1, {}) # expected expected_violations = [] self.assertEqual(expected_violations, actual_violations)
def test_org_proj_rules_vs_policy_has_violations(self): """Test rules on org and project with whitelist, blacklist, required. Test whitelist, blacklist, and required rules against an org that has 1 blacklist violation and a project that has 1 whitelist violation and 1 required violation. Setup: * Create a RulesEngine with RULES3 rule set. * Create policy. Expected result: * Find 3 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.RULES3) org_policy = { 'bindings': [{ 'role': 'roles/editor', 'members': [ 'user:[email protected]', 'user:[email protected]', ] }] } project_policy = { 'bindings': [{ 'role': 'roles/editor', 'members': [ 'user:[email protected]', 'user:[email protected]', ] }] } actual_violations = [] actual_violations.extend( rules_engine.find_policy_violations(self.org789, org_policy)) actual_violations.extend( rules_engine.find_policy_violations(self.project1, project_policy)) # expected expected_outstanding_org = { 'roles/editor': [IamPolicyMember.create_from('user:[email protected]')] } expected_outstanding_project = { 'roles/editor': [IamPolicyMember.create_from('user:[email protected]')], 'roles/viewer': [IamPolicyMember.create_from('user:[email protected]')] } expected_violations = [ RuleViolation(rule_index=1, rule_name='my blacklist rule', resource_id=self.org789.resource_id, resource_type=self.org789.resource_type, violation_type='ADDED', role=org_policy['bindings'][0]['role'], members=expected_outstanding_org['roles/editor']), RuleViolation( rule_index=0, rule_name='my whitelist rule', resource_id=self.project1.resource_id, resource_type=self.project1.resource_type, violation_type='ADDED', role=project_policy['bindings'][0]['role'], members=expected_outstanding_project['roles/editor']), RuleViolation( rule_index=2, rule_name='my required rule', resource_id=self.project1.resource_id, resource_type=self.project1.resource_type, violation_type='REMOVED', role='roles/viewer', members=expected_outstanding_project['roles/viewer']), ] self.assertItemsEqual(expected_violations, actual_violations)
def test_whitelist_blacklist_rules_vs_policy_has_violations(self): """Test a ruleset with whitelist and blacklist violating rules. Setup: * Create a RulesEngine with RULES2 rule set. * Create policy. Expected result: * Find 1 rule violation. """ # actual rules_local_path = get_datafile_path(__file__, 'test_rules_1.yaml') rules_engine = OrgRulesEngine(rules_local_path) rules_engine.rule_book = OrgRuleBook(self.RULES2) policy = { 'bindings': [{ 'role': 'roles/editor', 'members': [ 'user:[email protected]', 'user:[email protected]', 'user:[email protected]' ] }] } actual_violations = [] actual_violations.extend( rules_engine.find_policy_violations(self.project1, policy)) actual_violations.extend( rules_engine.find_policy_violations(self.project2, policy)) # expected expected_outstanding1 = { 'roles/editor': [IamPolicyMember.create_from('user:[email protected]')] } expected_outstanding2 = { 'roles/editor': [IamPolicyMember.create_from('user:[email protected]')] } expected_violations = [ RuleViolation(rule_index=0, rule_name='my rule', resource_id=self.project1.resource_id, resource_type=self.project1.resource_type, violation_type='ADDED', role=policy['bindings'][0]['role'], members=expected_outstanding1['roles/editor']), RuleViolation(rule_index=0, rule_name='my rule', resource_type=self.project2.resource_type, resource_id=self.project2.resource_id, violation_type='ADDED', role=policy['bindings'][0]['role'], members=expected_outstanding1['roles/editor']), RuleViolation(rule_index=1, rule_name='my other rule', resource_type=self.project2.resource_type, resource_id=self.project2.resource_id, violation_type='ADDED', role=policy['bindings'][0]['role'], members=expected_outstanding2['roles/editor']), RuleViolation(rule_index=2, rule_name='required rule', resource_id=self.project1.resource_id, resource_type=self.project1.resource_type, violation_type='REMOVED', role='roles/viewer', members=[ IamPolicyMember.create_from( 'user:[email protected]') ]) ] self.assertItemsEqual(expected_violations, actual_violations)
def test_build_rule_book_no_resource_type_fails(self): """Test that a rule without a resource type cannot be created.""" rules_local_path = get_datafile_path(__file__, 'test_rules_2.yaml') rules_engine = OrgRulesEngine(rules_file_path=rules_local_path) with self.assertRaises(InvalidRulesSchemaError): rules_engine.build_rule_book()
def test_build_rule_book_from_local_json_file_works(self): """Test that a RuleBook is built correctly with a json file.""" rules_local_path = get_datafile_path(__file__, 'test_rules_1.json') rules_engine = OrgRulesEngine(rules_file_path=rules_local_path) rules_engine.build_rule_book() self.assertEqual(4, len(rules_engine.rule_book.resource_rules_map))