Repository: cloud-custodian/cloud-custodian

Issue:
Security group CIDR when compare to 0.0.0.0/0 matches the source security groups as well
I have been implementing a policy to match the security groups that allow the source 0.0.0.0/0 for some vulnerable ports. However, the rule is also matching when the source field contains security group and not 0.0.0.0/0. Snippet of my config file looks like below.
```yaml
    filters:
      - or:
        - type: ingress
          Ports: [22]
          Cidr:
            value: 0.0.0.0/0
            op: eq
            value_type: cidr
 ```



Discussion:
Yes, I can reproduce this.

Resolving patch:
diff --git a/c7n/resources/vpc.py b/c7n/resources/vpc.py
--- a/c7n/resources/vpc.py
+++ b/c7n/resources/vpc.py
@@ -766,12 +766,16 @@ def process_ports(self, perm):
 
     def process_cidrs(self, perm):
         found = None
-        if 'IpRanges' in perm and 'Cidr' in self.data:
+        if 'Cidr' in self.data:
+            ip_perms = perm.get('IpRanges', [])
+            if not ip_perms:
+                return False
+
             match_range = self.data['Cidr']
             match_range['key'] = 'CidrIp'
             vf = ValueFilter(match_range)
             vf.annotate = False
-            for ip_range in perm.get('IpRanges', []):
+            for ip_range in ip_perms:
                 found = vf(ip_range)
                 if found:
                     break
@@ -812,6 +816,14 @@ def expand_permissions(self, permissions):
                     yield ep
 
     def __call__(self, resource):
+        def _accumulate(f, x):
+            '''
+            Accumulate an intermediate found value into the overall result.
+            '''
+            if x is not None:
+                f = (f is not None and x & f or x)
+            return f
+
         matched = []
         sg_id = resource['GroupId']
 
@@ -824,21 +836,11 @@ def __call__(self, resource):
                     found = False
                     break
             if found is None or found:
-                port_found = self.process_ports(perm)
-                if port_found is not None:
-                    found = (
-                        found is not None and port_found & found or port_found)
+                found = _accumulate(found, self.process_ports(perm))
             if found is None or found:
-                cidr_found = self.process_cidrs(perm)
-                if cidr_found is not None:
-                    found = (
-                        found is not None and cidr_found & found or cidr_found)
+                found = _accumulate(found, self.process_cidrs(perm))
             if found is None or found:
-                self_reference_found = self.process_self_reference(perm, sg_id)
-                if self_reference_found is not None:
-                    found = (
-                        found is not None and
-                        self_reference_found & found or self_reference_found)
+                found = _accumulate(found, self.process_self_reference(perm, sg_id))
             if not found:
                 continue
             matched.append(perm)


Test patch:
diff --git a/tests/test_vpc.py b/tests/test_vpc.py
--- a/tests/test_vpc.py
+++ b/tests/test_vpc.py
@@ -975,6 +975,145 @@ def test_ports_ingress(self):
         manager = p.get_resource_manager()
         self.assertEqual(len(manager.filter_resources(resources)), 1)
 
+    def test_self_reference_ingress_false_positives(self):
+        resources = [
+            {'Description': 'Typical Security Group',
+             'GroupId': 'sg-abcd1234',
+             'GroupName': 'TestSG',
+             'IpPermissions': [{'FromPort': 22,
+                                'IpProtocol': 'tcp',
+                                'IpRanges': [],
+                                'PrefixListIds': [],
+                                'ToPort': 22,
+                                'UserIdGroupPairs': [
+                                {'UserId': '123456789012', 'GroupId': 'sg-abcd1234'}]}],
+             'IpPermissionsEgress': [],
+             'OwnerId': '123456789012',
+             'Tags': [{'Key': 'Value',
+                       'Value': 'TypicalSecurityGroup'},
+                      {'Key': 'Key', 'Value': 'Name'}],
+             'VpcId': 'vpc-1234abcd'}
+        ]
+
+        p = self.load_policy({
+            'name': 'ingress-access',
+            'resource': 'security-group',
+            'filters': [
+                {'type': 'ingress',
+                 'Ports': [22],
+                 'SelfReference': True}
+                ]})
+        manager = p.get_resource_manager()
+        self.assertEqual(len(manager.filter_resources(resources)), 1)
+
+        p = self.load_policy({
+            'name': 'ingress-access',
+            'resource': 'security-group',
+            'filters': [
+                {'type': 'ingress',
+                 'Ports': [22],
+                 'SelfReference': False}
+                ]})
+        manager = p.get_resource_manager()
+        self.assertEqual(len(manager.filter_resources(resources)), 0)
+
+        p = self.load_policy({
+            'name': 'ingress-access',
+            'resource': 'security-group',
+            'filters': [
+                {'type': 'ingress',
+                 'Ports': [22],
+                 'Cidr': {
+                    'value': '0.0.0.0/0',
+                    'op': 'eq',
+                    'value_type': 'cidr'
+                 }}
+                ]})
+        manager = p.get_resource_manager()
+        self.assertEqual(len(manager.filter_resources(resources)), 0)
+
+        resources = [
+            {'Description': 'Typical Security Group',
+             'GroupId': 'sg-abcd1234',
+             'GroupName': 'TestSG',
+             'IpPermissions': [{'FromPort': 22,
+                                'IpProtocol': 'tcp',
+                                'IpRanges': [
+                                    {'CidrIp': '10.42.2.0/24'},
+                                    {'CidrIp': '10.42.4.0/24'},
+                                ],
+                                'PrefixListIds': [],
+                                'ToPort': 22,
+                                'UserIdGroupPairs': [
+                                {'UserId': '123456789012', 'GroupId': 'sg-abcd5678'}]}],
+             'IpPermissionsEgress': [],
+             'OwnerId': '123456789012',
+             'Tags': [{'Key': 'Value',
+                       'Value': 'TypicalSecurityGroup'},
+                      {'Key': 'Key', 'Value': 'Name'}],
+             'VpcId': 'vpc-1234abcd'}
+        ]
+
+        p = self.load_policy({
+            'name': 'ingress-access',
+            'resource': 'security-group',
+            'filters': [
+                {'type': 'ingress',
+                 'Ports': [22],
+                 'Cidr': {
+                    'value': '10.42.4.0/24',
+                    'op': 'eq',
+                    'value_type': 'cidr'
+                 }}
+                ]})
+        manager = p.get_resource_manager()
+        self.assertEqual(len(manager.filter_resources(resources)), 1)
+
+        p = self.load_policy({
+            'name': 'ingress-access',
+            'resource': 'security-group',
+            'filters': [
+                {'type': 'ingress',
+                 'Ports': [22],
+                 'Cidr': {
+                    'value': '10.42.3.0/24',
+                    'op': 'eq',
+                    'value_type': 'cidr'
+                 }}
+                ]})
+        manager = p.get_resource_manager()
+        self.assertEqual(len(manager.filter_resources(resources)), 0)
+
+        p = self.load_policy({
+            'name': 'ingress-access',
+            'resource': 'security-group',
+            'filters': [
+                {'type': 'ingress',
+                 'Ports': [22],
+                 'Cidr': {
+                    'value': '10.42.3.0/24',
+                    'op': 'ne',
+                    'value_type': 'cidr'
+                 }}
+                ]})
+        manager = p.get_resource_manager()
+        self.assertEqual(len(manager.filter_resources(resources)), 1)
+
+        p = self.load_policy({
+            'name': 'ingress-access',
+            'resource': 'security-group',
+            'filters': [
+                {'type': 'ingress',
+                 'Ports': [22],
+                 'Cidr': {
+                    'value': '0.0.0.0/0',
+                    'op': 'in',
+                    'value_type': 'cidr'
+                 }}
+                ]})
+        manager = p.get_resource_manager()
+        self.assertEqual(len(manager.filter_resources(resources)), 1)
+
     def test_permission_expansion(self):
         factory = self.replay_flight_data('test_security_group_perm_expand')
         client = factory().client('ec2')