def test_backend_service(self): """Test backend_service.Key.""" url_1 = ('https://www.googleapis.com/compute/v1/' 'projects/foo/global/backendServices/bar') url_2 = ('https://www.googleapis.com/compute/v1/' 'projects/foo/regions/bar/backendServices/baz') obj_1 = backend_service.BackendService(project_id='foo', name='bar') obj_2 = backend_service.BackendService(project_id='foo', region='bar', name='baz') key_1 = key.Key(backend_service.KEY_OBJECT_KIND, { 'project_id': 'foo', 'name': 'bar', 'region': None }) key_2 = key.Key(backend_service.KEY_OBJECT_KIND, { 'project_id': 'foo', 'name': 'baz', 'region': 'bar' }) self.assertEqual(key_1, obj_1.key) self.assertEqual(key_1, backend_service.Key.from_url(url_1)) self.assertEqual(key_2, obj_2.key) self.assertEqual(key_2, backend_service.Key.from_url(url_2)) url_invalid_1 = ('https://www.googleapis.com/compute/v1/' 'projects/foo') url_invalid_2 = ('https://www.googleapis.com/compute/v1/' 'backendServices/foo') self.assertRaises(ValueError, backend_service.Key.from_url, url_invalid_1) self.assertRaises(ValueError, backend_service.Key.from_url, url_invalid_2)
def test_direct_access_violation(self): rule = ire.Rule('my rule', 0, [], [], '^.*') resource_rule = ire.ResourceRules(self.org789, rules=set([rule]), applies_to='self_and_children') direct_source = 'some-tag' service = backend_service.BackendService(project_id=self.project1.id, name='bs1') iap_resource = iap_scanner.IapResource(backend_service=service, alternate_services=set(), direct_access_sources=set( [direct_source]), iap_enabled=True) results = list(resource_rule.find_mismatches(service, iap_resource)) expected_violations = [ ire.RuleViolation(resource_type='backend_service', resource_name='bs1', resource_id=service.resource_id, rule_name=rule.rule_name, rule_index=rule.rule_index, violation_type='IAP_VIOLATION', alternate_services_violations=[], direct_access_sources_violations=[direct_source], iap_enabled_violation=False), ] self.assertEquals(expected_violations, results)
def test_no_violations(self): rule = ire.Rule('my rule', 0, [], [], '^.*$') resource_rule = ire.ResourceRules(self.org789, rules=set([rule]), applies_to='self_and_children') service = backend_service.BackendService(project_id=self.project1.id, name='bs1') iap_resource = iap_scanner.IapResource(backend_service=service, alternate_services=set(), direct_access_sources=set(), iap_enabled=True) results = list(resource_rule.find_mismatches(service, iap_resource)) self.assertEquals([], results)
def test_violations_iap_disabled(self): """If IAP is disabled, don't report other violations.""" rule = ire.Rule('my rule', 0, [], [], '^.*') resource_rule = ire.ResourceRules(self.org789, rules=set([rule]), applies_to='self_and_children') service = backend_service.BackendService(project_id=self.project1.id, name='bs1') alternate_service = backend_service.Key.from_args( project_id=self.project1.id, name='bs2') iap_resource = iap_scanner.IapResource( backend_service=service, alternate_services=set([alternate_service]), direct_access_sources=set(['some-tag']), iap_enabled=False) results = list(resource_rule.find_mismatches(service, iap_resource)) expected_violations = [] self.assertEquals(expected_violations, results)
def setUp(self): self.fake_utcnow = datetime(year=1900, month=1, day=1, hour=0, minute=0, second=0, microsecond=0) # patch the daos self.org_patcher = mock.patch( 'google.cloud.security.common.data_access.' 'org_resource_rel_dao.OrgResourceRelDao') self.mock_org_rel_dao = self.org_patcher.start() self.mock_org_rel_dao.return_value = FakeOrgDao() self.project_patcher = mock.patch( 'google.cloud.security.common.data_access.' 'project_dao.ProjectDao') self.mock_project_dao = self.project_patcher.start() self.mock_project_dao.return_value = FakeProjectDao() self.fake_scanner_configs = {'output_path': 'gs://fake/output/path'} self.scanner = iap_scanner.IapScanner( {}, {}, '', get_datafile_path(__file__, 'iap_scanner_test_data.yaml')) self.scanner.scanner_configs = self.fake_scanner_configs self.scanner._get_backend_services = lambda: self.backend_services.values( ) self.scanner._get_firewall_rules = lambda: self.firewall_rules.values() self.scanner._get_instances = lambda: self.instances.values() self.scanner._get_instance_groups = lambda: self.instance_groups.values( ) self.scanner._get_instance_group_managers = lambda: self.instance_group_managers.values( ) self.scanner._get_instance_templates = lambda: self.instance_templates.values( ) self.backend_services = { # The main backend service. 'bs1': backend_service_type.BackendService( project_id='foo', name='bs1', backends=json.dumps([ { 'group': ('https://www.googleapis.com/compute/v1/' 'projects/foo/regions/wl-redqueen1/' 'instanceGroups/ig_managed') }, { 'group': ('https://www.googleapis.com/compute/v1/' 'projects/foo/regions/wl-redqueen1/' 'instanceGroups/ig_unmanaged') }, ]), iap=json.dumps({'enabled': True}), port=80, port_name='http', ), # Another backend service that connects to the same backend. 'bs1_same_backend': backend_service_type.BackendService( project_id='foo', name='bs1_same_backend', backends=json.dumps([ { 'group': ('https://www.googleapis.com/compute/v1/' 'projects/foo/regions/wl-redqueen1/' 'instanceGroups/ig_managed') }, ]), port=80, ), # A backend service with a different port (so, not an alternate). 'bs1_different_port': backend_service_type.BackendService( project_id='foo', name='bs1_different_port', backends=json.dumps([ { 'group': ('https://www.googleapis.com/compute/v1/' 'projects/foo/regions/wl-redqueen1/' 'instanceGroups/ig_managed') }, ]), port=81, ), # Various backend services that should or shouldn't be alts. 'bs1_same_instance': backend_service_type.BackendService( project_id='foo', name='bs1_same_instance', backends=json.dumps([ { 'group': ('https://www.googleapis.com/compute/v1/' 'projects/foo/regions/wl-redqueen1/' 'instanceGroups/ig_same_instance') }, ]), port=80, ), 'bs1_different_network': backend_service_type.BackendService( project_id='foo', name='bs1_different_network', backends=json.dumps([ { 'group': ('https://www.googleapis.com/compute/v1/' 'projects/foo/regions/wl-redqueen1/' 'instanceGroups/ig_different_network') }, ]), port=80, ), 'bs1_different_instance': backend_service_type.BackendService( project_id='foo', name='bs1_different_instance', backends=json.dumps([ { 'group': ('https://www.googleapis.com/compute/v1/' 'projects/foo/regions/wl-redqueen1/' 'instanceGroups/ig_different_instance') }, ]), port=80, ), } self.firewall_rules = { # Doesn't apply because of IPProtocol mismatch. 'proto_mismatch': firewall_rule_type.FirewallRule( project_id='foo', firewall_rule_name='proto_mismatch', firewall_rule_network='global/networks/default', firewall_rule_source_tags=json.dumps(['proto_mismatch']), firewall_rule_allowed=json.dumps([{ 'IPProtocol': 'udp', }]), ), # Preempted by allow. 'deny_applies_all_preempted': firewall_rule_type.FirewallRule( project_id='foo', firewall_rule_name='deny_applies_all_preempted', firewall_rule_priority=60000, firewall_rule_network='global/networks/default', firewall_rule_source_ranges=json.dumps(['applies_all']), firewall_rule_denied=json.dumps([{ 'IPProtocol': 'tcp', }]), ), # Applies to all ports, tags. 'applies_all': firewall_rule_type.FirewallRule( project_id='foo', firewall_rule_name='applies_all', firewall_rule_network='global/networks/default', firewall_rule_source_ranges=json.dumps(['10.0.2.0/24']), firewall_rule_source_tags=json.dumps(['applies_all']), firewall_rule_allowed=json.dumps([{ 'IPProtocol': 'tcp', }]), ), # Applies to only port 8080. 'applies_8080': firewall_rule_type.FirewallRule( project_id='foo', firewall_rule_name='applies_8080', firewall_rule_network='global/networks/default', firewall_rule_source_tags=json.dumps(['applies_8080']), firewall_rule_allowed=json.dumps([{ 'IPProtocol': 'tcp', 'ports': [8080], }]), ), # Applies to a multi-port range. 'applies_8081_8083': firewall_rule_type.FirewallRule( project_id='foo', firewall_rule_name='applies_8081_8083', firewall_rule_network='global/networks/default', firewall_rule_source_tags=json.dumps(['applies_8081_8083']), firewall_rule_allowed=json.dumps([{ 'IPProtocol': 'tcp', 'ports': ['8081-8083'], }]), ), # Doesn't apply because of direction mismatch. 'direction': firewall_rule_type.FirewallRule( project_id='foo', firewall_rule_name='direction', firewall_rule_direction='EGRESS', firewall_rule_network='global/networks/default', firewall_rule_source_tags=json.dumps(['direction']), firewall_rule_allowed=json.dumps([{ 'IPProtocol': 'tcp', }]), ), # Doesn't apply because of network mismatch. 'network': firewall_rule_type.FirewallRule( project_id='foo', firewall_rule_name='network', firewall_rule_network='global/networks/social', firewall_rule_source_tags=json.dumps(['network']), firewall_rule_allowed=json.dumps([{ 'IPProtocol': 'tcp', }]), ), # Doesn't apply because of tags. 'tag_mismatch': firewall_rule_type.FirewallRule( project_id='foo', firewall_rule_name='tag_mismatch', firewall_rule_network='global/networks/default', firewall_rule_source_tags=json.dumps(['tag_mismatch']), firewall_rule_target_tags=json.dumps( ['im_gonna_pop_some_tags']), firewall_rule_allowed=json.dumps([{ 'IPProtocol': 'tcp', }]), ), # Tag-specific rule *does* apply. 'tag_match': firewall_rule_type.FirewallRule( project_id='foo', firewall_rule_name='tag_match', firewall_rule_network='global/networks/default', firewall_rule_source_tags=json.dumps(['tag_match']), firewall_rule_target_tags=json.dumps(['tag_i1']), firewall_rule_allowed=json.dumps([{ 'IPProtocol': 'tcp', }]), ), # Preempted by deny rule. 'preempted': firewall_rule_type.FirewallRule( project_id='foo', firewall_rule_name='preempted', firewall_rule_network='global/networks/default', firewall_rule_source_tags=json.dumps(['preempted']), firewall_rule_allowed=json.dumps([{ 'IPProtocol': 'tcp', }]), ), # Preempted by deny rule. 'preempted_deny': firewall_rule_type.FirewallRule( project_id='foo', firewall_rule_name='preempted_deny', firewall_rule_priority=1, firewall_rule_network='global/networks/default', firewall_rule_source_ranges=json.dumps(['preempted']), firewall_rule_denied=json.dumps([{ 'IPProtocol': 'tcp', }]), ), } self.instances = { 'i1': instance_type.Instance( project_id='foo', name='i1', tags=json.dumps({'items': ['tag_i1']}), zone='wl-redqueen1-a', ), 'i2': instance_type.Instance( project_id='foo', name='i2', tags=json.dumps([]), zone='wl-redqueen1-a', ), } self.instance_groups = { # Managed 'ig_managed': instance_group_type.InstanceGroup( project_id='foo', name='ig_managed', network='global/networks/default', region='wl-redqueen1', instance_urls=json.dumps([ ('https://www.googleapis.com/compute/v1/' 'projects/foo/zones/wl-redqueen1-a/instances/i1') ]), ), # Unmanaged; overrides port mapping 'ig_unmanaged': instance_group_type.InstanceGroup( project_id='foo', name='ig_unmanaged', network='global/networks/default', region='wl-redqueen1', instance_urls=json.dumps([]), named_ports=json.dumps([{ 'name': 'foo', 'port': 80 }, { 'name': 'http', 'port': 8080 }]), ), # Unmanaged; same instance as ig_managed 'ig_same_instance': instance_group_type.InstanceGroup( project_id='foo', name='ig_same_instance', network='global/networks/default', region='wl-redqueen1', instance_urls=json.dumps([ ('https://www.googleapis.com/compute/v1/' 'projects/foo/zones/wl-redqueen1-a/instances/i1') ]), ), # Unmanaged; different network than ig_managed 'ig_different_network': instance_group_type.InstanceGroup( project_id='foo', name='ig_different_network', network='global/networks/nondefault', region='wl-redqueen1', instance_urls=json.dumps([ ('https://www.googleapis.com/compute/v1/' 'projects/foo/zones/wl-redqueen1-a/instances/i1') ]), ), # Unmanaged; different instance than ig_managed 'ig_different_instance': instance_group_type.InstanceGroup( project_id='foo', name='ig5', network='global/networks/default', region='wl-redqueen1', instance_urls=json.dumps([ ('https://www.googleapis.com/compute/v1/' 'projects/foo/zones/wl-redqueen1-a/instances/i2') ]), ), } self.instance_group_managers = { 'igm1': instance_group_manager_type.InstanceGroupManager( project_id='foo', name='igm1', instance_group= ('https://www.googleapis.com/compute/v1/' 'projects/foo/regions/wl-redqueen1/instanceGroups/ig_managed' ), instance_template=( 'https://www.googleapis.com/compute/v1/' 'projects/foo/global/instanceTemplates/it1'), region='wl-redqueen1', ), } self.instance_templates = { 'it1': instance_template_type.InstanceTemplate( project_id='foo', name='it1', properties=json.dumps({ 'tags': { 'items': ['tag_it1'] }, }), ), } self.data = iap_scanner._RunData( self.backend_services.values(), self.firewall_rules.values(), self.instances.values(), self.instance_groups.values(), self.instance_group_managers.values(), self.instance_templates.values(), )