예제 #1
0
    def test_extract_arns_from_statement_condition(self):
        test_condition_list = [
            'ArnEquals',
            'ForAllValues:ArnEquals',
            'ForAnyValue:ArnEquals',
            'ArnLike',
            'ForAllValues:ArnLike',
            'ForAnyValue:ArnLike',
            'StringLike',
            'ForAllValues:StringLike',
            'ForAnyValue:StringLike',
            'StringEquals',
            'ForAllValues:StringEquals',
            'ForAnyValue:StringEquals'
        ]

        bad_condition_list = [
            'NotACondition',
            'ArnLikeSomethingNotARealCondition'
        ]

        arn_types = [
            ('aws:sourcearn', 'arn:aws:s3:::some-s3-bucket'),
            ('aws:sourcearn', 'arn:aws:s3:::some-s3-bucket/*'),
            ('aws:sourcearn', "*"),
            ('aws:sourceowner', '012345678912'),
            ('aws:sourceowner', '*')
        ]

        for condition in test_condition_list:
            for arn_type in arn_types:
                test_condition = {
                    condition: {
                        arn_type[0]: arn_type[1]
                    }
                }

                result = ARN.extract_arns_from_statement_condition(test_condition)
                self.assertIsInstance(result, list)
                self.assertTrue(len(result) > 0)

        for condition in bad_condition_list:
            for arn_type in arn_types:
                test_condition = {
                    condition: {
                        arn_type[0]: arn_type[1]
                    }
                }

                result = ARN.extract_arns_from_statement_condition(test_condition)
                self.assertIsInstance(result, list)
                self.assertTrue(len(result) == 0)
예제 #2
0
    def check_sqsqueue_crossaccount(self, sqsitem):
        """
        alert on cross account access
        """
        policy = sqsitem.config
        for statement in policy.get("Statement", []):
            account_numbers = []
            princ = statement.get("Principal", None)
            if not princ:
                # It is possible not to define a principal, AWS ignores these statements.
                # We should raise an issue.
                tag = "SQS Policy is lacking Principal field"
                notes = json.dumps(statement)
                self.add_issue(5, tag, sqsitem, notes=notes)
                continue
            if isinstance(princ, dict):
                princ_val = princ.get("AWS") or princ.get("Service")
            else:
                princ_val = princ

            if princ_val == "*":
                condition = statement.get('Condition', {})
                arns = ARN.extract_arns_from_statement_condition(condition)
                if not arns:
                    tag = "SQS Queue open to everyone"
                    notes = "An SQS policy where { 'Principal': { 'AWS': '*' } } must also have"
                    notes += " a {'Condition': {'ArnEquals': { 'AWS:SourceArn': '<ARN>' } } }"
                    notes += " or it is open to the world. In this case, anyone is allowed to perform "
                    notes += " this action(s): {}".format(
                        statement.get("Action"))
                    self.add_issue(10, tag, sqsitem, notes=notes)

                for arn in arns:
                    self._parse_arn(arn, account_numbers, sqsitem)

            else:
                if isinstance(princ_val, list):
                    for entry in princ_val:
                        arn = ARN(entry)
                        if arn.error:
                            self.add_issue(3,
                                           'Auditor could not parse ARN',
                                           sqsitem,
                                           notes=entry)
                            continue

                        if not arn.service:
                            account_numbers.append(arn.account_number)
                else:
                    arn = ARN(princ_val)
                    if arn.error:
                        self.add_issue(3,
                                       'Auditor could not parse ARN',
                                       sqsitem,
                                       notes=princ_val)
                    elif not arn.service:
                        account_numbers.append(arn.account_number)

            for account_number in account_numbers:
                self._check_cross_account(account_number, sqsitem, 'policy')
예제 #3
0
    def check_snstopicpolicy_crossaccount(self, snsitem):
        """
        alert on cross account access
        """
        policy = snsitem.config.get('policy', {})
        for statement in policy.get("Statement", []):
            account_numbers = []
            princ = statement.get("Principal", {})
            if isinstance(princ, dict):
                princ_val = princ.get("AWS") or princ.get("Service")
            else:
                princ_val = princ

            if princ_val == "*":
                condition = statement.get('Condition', {})
                arns = ARN.extract_arns_from_statement_condition(condition)

                if not arns:
                    tag = "SNS Topic open to everyone"
                    notes = "An SNS policy where { 'Principal': { 'AWS': '*' } } must also have"
                    notes += " a {'Condition': {'StringEquals': { 'AWS:SourceOwner': '<ARN>' } } }"
                    notes += " or it is open to the world. In this case, anyone is allowed to perform "
                    notes += " this action(s): {}".format(
                        statement.get("Action"))
                    self.add_issue(10, tag, snsitem, notes=notes)

                for arn in arns:
                    self._parse_arn(arn, account_numbers, snsitem)

            else:
                if isinstance(princ_val, list):
                    for entry in princ_val:
                        arn = ARN(entry)
                        if arn.error:
                            self.add_issue(3,
                                           'Auditor could not parse ARN',
                                           snsitem,
                                           notes=entry)
                            continue

                        if not arn.service:
                            account_numbers.append(arn.account_number)
                else:
                    arn = ARN(princ_val)
                    if arn.error:
                        self.add_issue(3,
                                       'Auditor could not parse ARN',
                                       snsitem,
                                       notes=princ_val)
                    elif not arn.service:
                        account_numbers.append(arn.account_number)

            for account_number in account_numbers:
                self._check_cross_account(account_number, snsitem, 'policy')
예제 #4
0
    def check_sqsqueue_crossaccount(self, sqsitem):
        """
        alert on cross account access
        """
        policy = sqsitem.config
        for statement in policy.get("Statement", []):
            account_numbers = []
            princ = statement.get("Principal", None)
            if not princ:
                # It is possible not to define a principal, AWS ignores these statements.
                # We should raise an issue.
                tag = "SQS Policy is lacking Principal field"
                notes = json.dumps(statement)
                self.add_issue(5, tag, sqsitem, notes=notes)
                continue
            if isinstance(princ, dict):
                princ_val = princ.get("AWS") or princ.get("Service")
            else:
                princ_val = princ

            if princ_val == "*":
                condition = statement.get('Condition', {})
                arns = ARN.extract_arns_from_statement_condition(condition)
                if not arns:
                    tag = "SQS Queue open to everyone"
                    notes = "An SQS policy where { 'Principal': { 'AWS': '*' } } must also have"
                    notes += " a {'Condition': {'ArnEquals': { 'AWS:SourceArn': '<ARN>' } } }"
                    notes += " or it is open to the world. In this case, anyone is allowed to perform "
                    notes += " this action(s): {}".format(statement.get("Action"))
                    self.add_issue(10, tag, sqsitem, notes=notes)

                for arn in arns:
                    self._parse_arn(arn, account_numbers, sqsitem)

            else:
                if isinstance(princ_val, list):
                    for entry in princ_val:
                        arn = ARN(entry)
                        if arn.error:
                            self.add_issue(3, 'Auditor could not parse ARN', sqsitem, notes=entry)
                            continue

                        if not arn.service:
                            account_numbers.append(arn.account_number)
                else:
                    arn = ARN(princ_val)
                    if arn.error:
                        self.add_issue(3, 'Auditor could not parse ARN', sqsitem, notes=princ_val)
                    elif not arn.service:
                        account_numbers.append(arn.account_number)

            for account_number in account_numbers:
                self._check_cross_account(account_number, sqsitem, 'policy')
예제 #5
0
    def test_extract_arns_from_statement_condition(self):
        test_condition_list = [
            'ArnEquals', 'ForAllValues:ArnEquals', 'ForAnyValue:ArnEquals',
            'ArnLike', 'ForAllValues:ArnLike', 'ForAnyValue:ArnLike',
            'StringLike', 'ForAllValues:StringLike', 'ForAnyValue:StringLike',
            'StringEquals', 'ForAllValues:StringEquals',
            'ForAnyValue:StringEquals'
        ]

        bad_condition_list = [
            'NotACondition', 'ArnLikeSomethingNotARealCondition'
        ]

        arn_types = [('aws:sourcearn', 'arn:aws:s3:::some-s3-bucket'),
                     ('aws:sourcearn', 'arn:aws:s3:::some-s3-bucket/*'),
                     ('aws:sourcearn', "*"),
                     ('aws:sourceowner', '012345678912'),
                     ('aws:sourceowner', '*')]

        for condition in test_condition_list:
            for arn_type in arn_types:
                test_condition = {condition: {arn_type[0]: arn_type[1]}}

                result = ARN.extract_arns_from_statement_condition(
                    test_condition)
                self.assertIsInstance(result, list)
                self.assertTrue(len(result) > 0)

        for condition in bad_condition_list:
            for arn_type in arn_types:
                test_condition = {condition: {arn_type[0]: arn_type[1]}}

                result = ARN.extract_arns_from_statement_condition(
                    test_condition)
                self.assertIsInstance(result, list)
                self.assertTrue(len(result) == 0)
예제 #6
0
    def check_snstopicpolicy_crossaccount(self, snsitem):
        """
        alert on cross account access
        """
        policy = snsitem.config.get('policy', {})
        for statement in policy.get("Statement", []):
            account_numbers = []
            princ = statement.get("Principal", {})
            if isinstance(princ, dict):
                princ_val = princ.get("AWS") or princ.get("Service")
            else:
                princ_val = princ

            if princ_val == "*":
                condition = statement.get('Condition', {})
                arns = ARN.extract_arns_from_statement_condition(condition)

                if not arns:
                    tag = "SNS Topic open to everyone"
                    notes = "An SNS policy where { 'Principal': { 'AWS': '*' } } must also have"
                    notes += " a {'Condition': {'StringEquals': { 'AWS:SourceOwner': '<ARN>' } } }"
                    notes += " or it is open to the world. In this case, anyone is allowed to perform "
                    notes += " this action(s): {}".format(statement.get("Action"))
                    self.add_issue(10, tag, snsitem, notes=notes)

                for arn in arns:
                    self._parse_arn(arn, account_numbers, snsitem)

            else:
                if isinstance(princ_val, list):
                    for entry in princ_val:
                        arn = ARN(entry)
                        if arn.error:
                            self.add_issue(3, 'Auditor could not parse ARN', snsitem, notes=entry)
                            continue

                        if not arn.service:
                            account_numbers.append(arn.account_number)
                else:
                    arn = ARN(princ_val)
                    if arn.error:
                        self.add_issue(3, 'Auditor could not parse ARN', snsitem, notes=princ_val)
                    elif not arn.service:
                        account_numbers.append(arn.account_number)

            for account_number in account_numbers:
                self._check_cross_account(account_number, snsitem, 'policy')