def check_internet_accessible(self, item):
     policies = self.load_resource_policies(item)
     for policy in policies:
         if policy.is_internet_accessible():
             entity = Entity(category='principal', value='*')
             actions = list(policy.internet_accessible_actions())
             self.record_internet_access(item, entity, actions)
Exemplo n.º 2
0
 def check_friendly_access(self, item):
     for uid in self._get_permissions(item):
         entity = Entity(category='account', value=uid)
         if 'FRIENDLY' in self.inspect_entity(entity, item):
             self.record_friendly_access(item,
                                         entity,
                                         actions=['createEBSVolume'])
Exemplo n.º 3
0
    def check_acl_unknown(self, item):
        acl = item.config.get('Grants', {})

        for key in acl.keys():
            if key.lower() not in self.KNOWN_ACLS:
                entity = Entity(category='ACL', value=key)
                self.record_unknown_access(item, entity, actions=acl[key])
Exemplo n.º 4
0
 def check_thirdparty_access(self, item):
     for uid in self._get_permissions(item):
         entity = Entity(category='account', value=uid)
         if 'THIRDPARTY' in self.inspect_entity(entity, item):
             self.record_thirdparty_access(item,
                                           entity,
                                           actions=['createEBSVolume'])
Exemplo n.º 5
0
    def _check_internet_accessible(self,
                                   item,
                                   direction='ingress',
                                   severity=10):
        """
        Make sure the SG does not contain any 0.0.0.0/0 or ::/0 rules.

        Called by:
            check_internet_accessible_ingress()
            check_internet_accessible_egress()

        Returns:
            `none`
        """
        multiplier = _check_empty_security_group(item)
        score = severity * multiplier

        for rule in item.config.get("rules", []):
            if not rule.get("rule_type") == direction:
                continue

            cidr = rule.get("cidr_ip")
            if not str(cidr).endswith('/0'):
                continue

            actions = self._port_for_rule(rule)
            entity = Entity(category='cidr', value=cidr)
            self.record_internet_access(item,
                                        entity,
                                        actions,
                                        score=score,
                                        source='security_group')
Exemplo n.º 6
0
    def _check_acl(self, item, field, keys, recorder):
        acl = item.config.get('Grants', {})
        owner = item.config["Owner"]["ID"].lower()
        for key in acl.keys():
            if key.lower() not in keys:
                continue

            # Canonical ID == Owning Account - No issue
            if key.lower() == owner.lower():
                continue

            entity = Entity(category='ACL', value=key)
            account = self._get_account(field, key)
            if account:
                entity.account_name=account['name']
                entity.account_identifier=account['identifier']
            recorder(item, actions=acl[key], entity=entity)
Exemplo n.º 7
0
    def _check_acl(self, item, field, keys, recorder):
        acl = item.config.get('Grants', {})
        owner = item.config["Owner"]["ID"].lower()
        for key in acl.keys():
            if key.lower() not in keys:
                continue

            # Canonical ID == Owning Account - No issue
            if key.lower() == owner.lower():
                continue

            entity = Entity(category='ACL', value=key)
            account = self._get_account(field, key)
            if account:
                entity.account_name = account['name']
                entity.account_identifier = account['identifier']
            recorder(item, actions=acl[key], entity=entity)
Exemplo n.º 8
0
    def check_unknown_cross_account(self, item):
        accounts = item.config.get('Attributes', {}).get('restore', [])
        for account in accounts:
            if account == 'all':
                continue

            if account not in self.FRIENDLY and account not in self.THIRDPARTY:
                entity = Entity(category='account', value=account)
                self.record_unknown_access(item, entity, actions=['restore'])
Exemplo n.º 9
0
 def check_internet_accessible(self, item):
     accounts = {
         lp.get('UserId', lp.get('Group'))
         for lp in item.config.get('LaunchPermissions')
     }
     if 'all' in accounts or item.config.get('Public') == True:
         entity = Entity(category='account', value='all')
         self.record_internet_access(item,
                                     entity,
                                     actions=['LaunchPermissions'])
 def check_thirdparty_cross_account(self, item):
     policies = self.load_resource_policies(item)
     for policy in policies:
         for statement in policy.statements:
             if statement.effect != 'Allow':
                 continue
             for who in statement.whos_allowed():
                 entity = Entity.from_tuple(who)
                 if 'THIRDPARTY' in self.inspect_entity(entity, item):
                     self.record_thirdparty_access(item, entity, list(statement.actions))
    def check_unknown_cross_account(self, item):
        accounts = {lp.get('UserId', lp.get('Group')) for lp in item.config.get('LaunchPermissions', [])}
        for account in accounts:
            if account == 'all':
                continue

            if account not in self.FRIENDLY and account not in self.THIRDPARTY:
                entity = Entity(
                    category='account',
                    value=account)
                self.record_unknown_access(item, entity, actions=['LaunchPermissions'])
Exemplo n.º 12
0
    def check_subscriptions_crossaccount(self, item):
        """
        "subscriptions": [
          {
               "Owner": "020202020202",
               "Endpoint": "*****@*****.**",
               "Protocol": "email",
               "TopicArn": ARN_PREFIX + ":sns:" + AWS_DEFAULT_REGION + ":020202020202:somesnstopic",
               "SubscriptionArn": ARN_PREFIX + ":sns:" + AWS_DEFAULT_REGION + ":020202020202:somesnstopic:..."
          }
        ]
        """
        subscriptions = item.config.get('subscriptions', [])
        for subscription in subscriptions:
            src_account_number = subscription.get('Owner', None)

            entity = Entity(category=subscription.get('Protocol'),
                            value=subscription.get('Endpoint'),
                            account_identifier=src_account_number,
                            account_name='UNKNOWN')

            account = self._get_account('identifier', src_account_number)
            if not account:
                self.record_unknown_access(item,
                                           entity,
                                           actions=['subscription'])
                continue

            if account['name'] == item.account:
                # Same Account
                continue

            entity.account_name = account['name']
            if account['label'] == 'friendly':
                self.record_friendly_access(item,
                                            entity,
                                            actions=['subscription'])
            elif account['label'] == 'thirdparty':
                self.record_thirdparty_access(item,
                                              entity,
                                              actions=['subscription'])
Exemplo n.º 13
0
    def check_unknown_access(self, item):
        for uid in self._get_permissions(item):

            # handled as a special case of internet accessible access.
            if 'aws-marketplace' == uid:
                continue

            entity = Entity(category='account', value=uid)
            if 'UNKNOWN' in self.inspect_entity(entity, item):
                self.record_unknown_access(item,
                                           entity,
                                           actions=['createEBSVolume'])
Exemplo n.º 14
0
    def check_friendly_cross_account(self, item):
        accounts = item.config.get('Attributes', {}).get('restore', [])
        for account in accounts:
            if account == 'all':
                continue

            if account in self.FRIENDLY:
                entity = Entity(category='account',
                                value=account,
                                account_name=self.FRIENDLY[account],
                                account_identifier=account)
                self.record_friendly_access(item, entity, actions=['restore'])
    def check_thirdparty_cross_account(self, item):
        accounts = {lp.get('UserId', lp.get('Group')) for lp in item.config.get('LaunchPermissions', [])}
        for account in accounts:
            if account == 'all':
                continue

            if account in self.THIRDPARTY:
                entity = Entity(
                    category='account',
                    value=account,
                    account_name=self.THIRDPARTY[account],
                    account_identifier=account)
                self.record_thirdparty_access(item, entity, actions=['LaunchPermissions'])
 def check_root_cross_account(self, item):
     policies = self.load_resource_policies(item)
     for policy in policies:
         for statement in policy.statements:
             if statement.effect != 'Allow':
                 continue
             for who in statement.whos_allowed():
                 if who.category not in ['arn', 'principal']:
                     continue
                 if who.value == '*':
                     continue
                 arn = ARN(who.value)
                 entity = Entity.from_tuple(who)
                 if arn.root and self.inspect_entity(entity, item).intersection(set(['FRIENDLY', 'THIRDPARTY', 'UNKNOWN'])):
                     self.record_cross_account_root(item, entity, list(statement.actions))
Exemplo n.º 17
0
    def check_subscriptions_crossaccount(self, item):
        """
        "subscriptions": [
          {
               "Owner": "020202020202",
               "Endpoint": "*****@*****.**",
               "Protocol": "email",
               "TopicArn": ARN_PREFIX + ":sns:" + AWS_DEFAULT_REGION + ":020202020202:somesnstopic",
               "SubscriptionArn": ARN_PREFIX + ":sns:" + AWS_DEFAULT_REGION + ":020202020202:somesnstopic:..."
          }
        ]
        """
        subscriptions = item.config.get('subscriptions', [])
        for subscription in subscriptions:
            src_account_number = subscription.get('Owner', None)

            entity = Entity(
                category=subscription.get('Protocol'),
                value=subscription.get('Endpoint'),
                account_identifier=src_account_number,
                account_name='UNKNOWN')

            account = self._get_account('identifier', src_account_number)
            if not account:
                self.record_unknown_access(item, entity, actions=['subscription'])
                continue

            if account['name'] == item.account:
                # Same Account
                continue

            entity.account_name = account['name']
            if account['label'] == 'friendly':
                self.record_friendly_access(item, entity, actions=['subscription'])
            elif account['label'] == 'thirdparty':
                self.record_thirdparty_access(item, entity, actions=['subscription'])
    def check_unknown_cross_account(self, item):
        policies = self.load_resource_policies(item)
        for policy in policies:
            if policy.is_internet_accessible():
                continue
            for statement in policy.statements:
                if statement.effect != 'Allow':
                    continue
                for who in statement.whos_allowed():
                    if who.value == '*' and who.category == 'principal':
                        continue

                    # Ignore Service Principals
                    if who.category == 'principal':
                        arn = ARN(who.value)
                        if arn.service:
                            continue

                    entity = Entity.from_tuple(who)
                    if 'UNKNOWN' in self.inspect_entity(entity, item):
                        self.record_unknown_access(item, entity, list(statement.actions))
    def test_inspect_entity(self):
        rpa = ResourcePolicyAuditor(accounts=["012345678910"])
        rpa.prep_for_audit()

        # All conditions are SAME account.
        policy01 = dict(
            Version='2010-08-14',
            Statement=[
                dict(Effect='Allow',
                     Principal='arn:aws:iam::012345678910:root',
                     Action=['ec2:*'],
                     Resource='*',
                     Condition={
                         'StringEquals': {
                             'AWS:SourceOwner': '012345678910',
                             'AWS:SourceARN': 'arn:aws:iam::012345678910:root',
                             'AWS:SourceVPC': 'vpc-11111111',
                             'AWS:Sourcevpce': 'vpce-11111111',
                             'AWS:username': '******'
                         },
                         'StringLike': {
                             'AWS:userid': [
                                 'AIDA11111111111111111:*',
                                 'AISA11111111111111111:*'
                             ]
                         },
                         'IpAddress': {
                             'AWS:SourceIP':
                             ['54.11.11.11', '10.1.1.1/18', '172.16.11.11']
                         }
                     })
            ])

        test_item = Item(account='TEST_ACCOUNT', config=None)
        policy = Policy(policy01)
        for who in policy.whos_allowed():
            entity = Entity.from_tuple(who)
            self.assertEqual(set(['SAME']),
                             rpa.inspect_entity(entity, test_item))

        # All conditions are FRIENDLY account.
        policy02 = dict(
            Version='2010-08-14',
            Statement=[
                dict(Effect='Allow',
                     Principal='arn:aws:iam::222222222222:root',
                     Action=['ec2:*'],
                     Resource='*',
                     Condition={
                         'StringEquals': {
                             'AWS:SourceOwner': '222222222222',
                             'AWS:SourceARN':
                             'arn:aws:s3:::my-test-s3-bucket-two',
                             'AWS:SourceVPC': 'vpc-22222222',
                             'AWS:Sourcevpce': 'vpce-22222222',
                             'AWS:username': '******'
                         },
                         'StringLike': {
                             'AWS:userid': [
                                 'AIDA22222222222222222:*',
                                 'AISA22222222222222222:*'
                             ]
                         },
                         'IpAddress': {
                             'AWS:SourceIP':
                             ['54.22.22.22', '10.2.2.2/18', '172.16.22.22']
                         }
                     })
            ])

        test_item = Item(account='TEST_ACCOUNT', config=None)
        policy = Policy(policy02)
        for who in policy.whos_allowed():
            entity = Entity.from_tuple(who)
            self.assertEqual(set(['FRIENDLY']),
                             rpa.inspect_entity(entity, test_item))

        # All conditions are THIRDPARTY account.
        policy03 = dict(
            Version='2010-08-14',
            Statement=[
                dict(Effect='Allow',
                     Principal='arn:aws:iam::333333333333:root',
                     Action=['ec2:*'],
                     Resource='*',
                     Condition={
                         'StringEquals': {
                             'AWS:SourceOwner': '333333333333',
                             'AWS:SourceARN': 'arn:aws:iam::333333333333:root',
                             'AWS:SourceVPC': 'vpc-33333333',
                             'AWS:Sourcevpce': 'vpce-33333333',
                             'AWS:username': '******'
                         },
                         'StringLike': {
                             'AWS:userid': [
                                 'AIDA33333333333333333:*',
                                 'AISA33333333333333333:*'
                             ]
                         },
                         'IpAddress': {
                             'AWS:SourceIP':
                             ['54.33.33.33', '10.3.3.3/18', '172.16.33.33']
                         }
                     })
            ])

        test_item = Item(account='TEST_ACCOUNT', config=None)
        policy = Policy(policy03)
        for who in policy.whos_allowed():
            entity = Entity.from_tuple(who)
            self.assertEqual(set(['THIRDPARTY']),
                             rpa.inspect_entity(entity, test_item))

        # All conditions are from an UNKNOWN account.
        policy04 = dict(
            Version='2010-08-14',
            Statement=[
                dict(Effect='Allow',
                     Principal='arn:aws:iam::444444444444:root',
                     Action=['ec2:*'],
                     Resource='*',
                     Condition={
                         'StringEquals': {
                             'AWS:SourceOwner': '444444444444',
                             'AWS:SourceARN': 'arn:aws:iam::444444444444:root',
                             'AWS:SourceVPC': 'vpc-44444444',
                             'AWS:Sourcevpce': 'vpce-44444444',
                             'AWS:username': '******'
                         },
                         'StringLike': {
                             'AWS:userid': [
                                 'AIDA44444444444444444:*',
                                 'AISA44444444444444444:*'
                             ]
                         },
                         'IpAddress': {
                             'AWS:SourceIP':
                             ['54.44.44.44', '10.4.4.4/18', '172.16.44.44']
                         }
                     })
            ])

        test_item = Item(account='TEST_ACCOUNT', config=None)
        policy = Policy(policy04)
        for who in policy.whos_allowed():
            entity = Entity.from_tuple(who)
            self.assertEqual(set(['UNKNOWN']),
                             rpa.inspect_entity(entity, test_item))
Exemplo n.º 20
0
 def check_internet_accessible(self, item):
     if 'all' in item.config.get('Attributes', {}).get('restore', []):
         entity = Entity(category='account', value='all')
         self.record_internet_access(item, entity, actions=['restore'])
Exemplo n.º 21
0
 def check_marketplace_access(self, item):
     if 'aws-marketplace' in self._get_permissions(item):
         entity = Entity(category='shared_ebs', value='aws-marketplace')
         self.record_internet_access(item,
                                     entity,
                                     actions=['createEBSVolume'])
Exemplo n.º 22
0
 def check_internet_accessible(self, item):
     if 'all' in self._get_permissions(item, key='Group'):
         entity = Entity(category='shared_ebs', value='public')
         self.record_internet_access(item,
                                     entity,
                                     actions=['createEBSVolume'])
Exemplo n.º 23
0
    def _check_cross_account(self,
                             item,
                             key,
                             recorder,
                             direction='ingress',
                             severity=10):
        """
        Inspects each rule to look for cross account access.

        Called by:
            - check_friendly_cross_account_*
            - check_thirdparty_cross_account_*
            - check_unknown_cross_account_*

        Looks at both CIDR rules and rules referencing other security groups.

        Args:
            item: ChangeItem containing a config member with rules to review.
            key: One of ['FRIENDLY', 'THIRDPARTY', 'UNKNOWN'].  When Auditor::inspect_entity()
                returns a set containing the provided key, the recorder method will be invoked.
            recorder: method to invoke to record an issue.  Should be one of:
                Auditor::record_friendly_access()
                Auditor::record_thirdparty_access()
                Auditor::record_unknown_access()
            direction: Either `ingress` or `egress` matching the rule type to inspect.
            severity: Maximum score to record issue as.  If the SG is not attached
                to any instances, the final final score may be reduced.

        Returns:
            `none`
        """
        multiplier = _check_empty_security_group(item)
        score = severity * multiplier

        for rule in item.config.get("rules", []):
            if rule.get("rule_type") != direction:
                continue

            ports = self._port_for_rule(rule)
            if rule.get('owner_id'):
                entity_value = '{account}/{sg}'.format(
                    account=rule.get('owner_id'), sg=rule.get('group_id'))
                entity = Entity(category='security_group', value=entity_value)
                if key in self.inspect_entity(entity, item):
                    recorder(item,
                             entity,
                             ports,
                             score=score,
                             source='security_group')

            if rule.get('cidr_ip'):
                if '/0' in rule.get('cidr_ip'):
                    continue

                entity = Entity(category='cidr', value=rule.get('cidr_ip'))
                if key in self.inspect_entity(entity, item):
                    recorder(item,
                             entity,
                             ports,
                             score=score,
                             source='security_group')