示例#1
0
    def resource_invoke(self,
                        resource: S3BucketPolicy,
                        logical_id: str,
                        extras: Optional[Dict] = None) -> Result:
        result = Result()

        for statement in resource.Properties.PolicyDocument._statement_as_list(
        ):
            for principal in statement.get_principal_list():
                account_id = get_account_id_from_principal(principal)
                if not account_id:
                    continue
                if account_id not in self.valid_principals:
                    if statement.Condition and statement.Condition.dict():
                        # Ignoring condition checks since they will get reviewed in other rules and future improvements
                        pass
                    else:
                        self.add_failure_to_result(
                            result,
                            self.REASON.format(logical_id, account_id),
                            resource_ids={logical_id},
                            resource_types={resource.Type},
                            context={
                                "config": self._config,
                                "extras": extras,
                                "logical_id": logical_id,
                                "resource": resource,
                                "statement": statement,
                                "principal": principal,
                                "account_id": account_id,
                            },
                        )
        return result
示例#2
0
def test_correct_event():
    event = {"stack_template_url": "https://asdfasdfasdf/bucket/key", "stack": {"name": "blooblah"}}

    mock_created_s3_adapter_object = Mock()
    mock_created_s3_adapter_object.download_template_to_dictionary.return_value = {"Resources": {}}
    mock_boto3_adapter = Mock(return_value=mock_created_s3_adapter_object)

    mock_created_boto3_client_object = Mock()
    mock_created_boto3_client_object.get_template.return_value = {"Resources": {}}
    mock_created_boto3_client_object.compare_outputs.return_value = {}
    mock_boto3_client = Mock(return_value=mock_created_boto3_client_object)

    mock_created_rule_processor_object = Mock(spec=RuleProcessor)
    mock_created_rule_processor_object.process_cf_template.return_value = Result()
    mock_rule_processor = Mock(return_value=mock_created_rule_processor_object)
    mock_rule_processor.remove_debug_rules.return_value = []

    with patch("cfripper.main.Boto3Client", new=mock_boto3_adapter):
        with patch("cfripper.main.RuleProcessor", new=mock_rule_processor):
            with patch("cfripper.main.Boto3Client", new=mock_boto3_client):
                from cfripper.main import handler

            handler(event, None)

    cfmodel = pycfmodel.parse({"Resources": {}}).resolve()
    mock_created_s3_adapter_object.download_template_to_dictionary.assert_called_once_with(
        "https://asdfasdfasdf/bucket/key"
    )
    mock_created_rule_processor_object.process_cf_template.assert_called_once_with(cfmodel, ANY)
示例#3
0
    def resource_invoke(self,
                        resource: S3BucketPolicy,
                        logical_id: str,
                        extras: Optional[Dict] = None) -> Result:
        result = Result()

        for statement in resource.Properties.PolicyDocument._statement_as_list(
        ):
            for principal in statement.get_principal_list():
                account_id = get_account_id_from_principal(principal)
                if not account_id:
                    continue
                if account_id not in self.valid_principals:
                    if statement.Condition and statement.Condition.dict():
                        logger.warning(
                            f"Not adding {type(self).__name__} failure in {logical_id} "
                            f"because there are conditions: {statement.Condition}"
                        )
                    else:
                        self.add_failure_to_result(
                            result,
                            self.REASON.format(logical_id, account_id),
                            resource_ids={logical_id},
                            context={
                                "config": self._config,
                                "extras": extras,
                                "logical_id": logical_id,
                                "resource": resource,
                                "statement": statement,
                                "principal": principal,
                                "account_id": account_id,
                            },
                        )
        return result
示例#4
0
    def invoke(self,
               cfmodel: CFModel,
               extras: Optional[Dict] = None) -> Result:
        result = Result()
        for logical_id, resource in cfmodel.Resources.items():
            if isinstance(resource, KMSKey):
                # Ignoring KMSKey because there's already a rule for it `KMSKeyWildcardPrincipalRule`
                continue
            if isinstance(resource, IAMRole):
                # Checking the `AssumeRolePolicyDocument` for IAM Roles
                self.check_for_wildcards(
                    result=result,
                    logical_id=logical_id,
                    resource=resource.Properties.AssumeRolePolicyDocument,
                    resource_type=resource.Type,
                    extras=extras,
                )
            for policy in resource.policy_documents:
                self.check_for_wildcards(
                    result=result,
                    logical_id=logical_id,
                    resource=policy.policy_document,
                    resource_type=resource.Type,
                    extras=extras,
                )

        return result
示例#5
0
def test_only_whitelisted_resources_are_removed(mock_rule_to_resource_whitelist):
    config = Config(
        stack_name="otherstack",
        rules=["S3CrossAccountTrustRule"],
        rule_to_resource_whitelist=mock_rule_to_resource_whitelist,
    )

    result = Result()
    failed_rules = [
        Failure(
            rule="S3CrossAccountTrustRule",
            reason="Forbidden cross-account policy allow with 123456789 for an S3 bucket.",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            resource_ids={"rolething", "thenotwhitelistedthing", "anotherone"},
            actions=None,
            granularity=RuleGranularity.RESOURCE,
        )
    ]
    result.failed_rules = failed_rules

    RuleProcessor.remove_failures_of_whitelisted_resources(config=config, result=result)
    assert result.failed_rules == [
        Failure(
            rule="S3CrossAccountTrustRule",
            reason="Forbidden cross-account policy allow with 123456789 for an S3 bucket.",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            resource_ids={"thenotwhitelistedthing", "anotherone"},
            actions=None,
            granularity=RuleGranularity.RESOURCE,
        )
    ]
def test_with_invalid_role_inline_policy_fn_if():
    role_props = {
        "AWSTemplateFormatVersion": "2010-09-09",
        "Resources": {
            "RootRole": {
                "Type": "AWS::IAM::Role",
                "Properties": {
                    "Path":
                    "/",
                    "Policies": [{
                        "Fn::If": [
                            "IsSandbox",
                            {
                                "PolicyDocument": {
                                    "Statement": [{
                                        "Action":
                                        "sts:AssumeRole",
                                        "Effect":
                                        "Allow",
                                        "Resource":
                                        "arn:aws:iam::325714046698:role/sandbox-secrets-access",
                                    }],
                                    "Version":
                                    "2012-10-17",
                                },
                                "PolicyName": "SandboxSecretsAccessAssumerole",
                            },
                            {
                                "PolicyDocument": {
                                    "Statement": [{
                                        "Action": ["ec2:DeleteVpc"],
                                        "Effect": "Allow",
                                        "Resource": ["*"]
                                    }],
                                    "Version":
                                    "2012-10-17",
                                },
                                "PolicyName":
                                "ProdCredentialStoreAccessPolicy",
                            },
                        ]
                    }],
                },
            }
        },
    }

    result = Result()
    rule = IAMRolesOverprivilegedRule(None, result)
    rule.check_managed_policies = Mock()
    resources = pycfmodel.parse(role_props).resources
    rule.invoke(resources, [])
    rule.check_managed_policies.assert_called()

    assert not result.valid
    assert (
        result.failed_rules[0]["reason"] ==
        'Role "RootRole" contains an insecure permission "ec2:DeleteVpc" in policy "ProdCredentialStoreAccessPolicy"'
    )
    assert result.failed_rules[0]["rule"] == "IAMRolesOverprivilegedRule"
示例#7
0
 def resource_invoke(self,
                     resource: SQSQueuePolicy,
                     logical_id: str,
                     extras: Optional[Dict] = None) -> Result:
     result = Result()
     if resource.Properties.PolicyDocument.allowed_principals_with(
             REGEX_HAS_STAR_OR_STAR_AFTER_COLON):
         for statement in resource.Properties.PolicyDocument._statement_as_list(
         ):
             if statement.Effect == "Allow" and statement.principals_with(
                     REGEX_HAS_STAR_OR_STAR_AFTER_COLON):
                 if statement.Condition and statement.Condition.dict():
                     logger.warning(
                         f"Not adding {type(self).__name__} failure in {logical_id} "
                         f"because there are conditions: {statement.Condition}"
                     )
                 else:
                     self.add_failure_to_result(
                         result,
                         self.REASON.format(logical_id),
                         resource_ids={logical_id},
                         context={
                             "config": self._config,
                             "extras": extras,
                             "logical_id": logical_id,
                             "resource": resource,
                             "statement": statement,
                         },
                     )
     return result
示例#8
0
 def invoke(self,
            cfmodel: CFModel,
            extras: Optional[Dict] = None) -> Result:
     result = Result()
     for logical_id, resource in cfmodel.Resources.items():
         if isinstance(resource, S3BucketPolicy):
             for statement in resource.Properties.PolicyDocument._statement_as_list(
             ):
                 for principal in statement.get_principal_list():
                     account_id = get_account_id_from_principal(principal)
                     if not account_id:
                         continue
                     if account_id not in self.valid_principals:
                         if statement.Condition and statement.Condition.dict(
                         ):
                             logger.warning(
                                 f"Not adding {type(self).__name__} failure in {logical_id} "
                                 f"because there are conditions: {statement.Condition}"
                             )
                         else:
                             self.add_failure_to_result(
                                 result,
                                 self.REASON.format(logical_id, account_id),
                                 resource_ids={logical_id},
                             )
     return result
示例#9
0
 def invoke(self,
            cfmodel: CFModel,
            extras: Optional[Dict] = None) -> Result:
     result = Result()
     if self.AWS_RESOURCE is None:
         logger.warning(
             f"Not running {type(self).__name__} rule as AWS_RESOURCE is not defined."
         )
     else:
         for logical_id, resource in cfmodel.Resources.items():
             if isinstance(
                     resource, self.AWS_RESOURCE
             ) and resource.Properties.PolicyDocument.allowed_actions_with(
                     REGEX_HAS_STAR_OR_STAR_AFTER_COLON):
                 self.add_failure_to_result(
                     result,
                     self.REASON.format(self.AWS_RESOURCE.__name__,
                                        logical_id),
                     resource_ids={logical_id},
                     context={
                         "config": self._config,
                         "extras": extras,
                         "logical_id": logical_id,
                         "resource": resource,
                     },
                     resource_types={resource.Type},
                 )
     return result
示例#10
0
def test_with_valid_role_inline_policy():
    role_props = {
        "AWSTemplateFormatVersion": "2010-09-09",
        "Resources": {
            "RootRole": {
                "Type": "AWS::IAM::Policy",
                "Properties": {
                    "PolicyName": "root",
                    "PolicyDocument": {
                        "Version":
                        "2012-10-17",
                        "Statement": [{
                            "Effect":
                            "Allow",
                            "Action": ["IAM:CREATEPOLICY"],
                            "Resource":
                            ["arn:aws:glue:eu-west-1:12345678:catalog"],
                        }],
                    },
                    "Roles": "some_role",
                },
            }
        },
    }

    resource = pycfmodel.parse(role_props).resources

    result = Result()
    rule = PrivilegeEscalationRule(None, result)

    rule.invoke(resource, [])

    assert not result.valid
    assert len(result.failed_rules) == 1
示例#11
0
    def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result:
        result = Result()
        for logical_id, resource in cfmodel.Resources.items():
            if isinstance(resource, S3BucketPolicy) and resource.Properties.PolicyDocument.allowed_actions_with(
                re.compile(r"^s3:L.*$")
            ):
                bucket_name = resource.Properties.Bucket
                if not isinstance(bucket_name, str):
                    logger.warning(f"Not adding {type(self).__name__} failure in {logical_id} – try resolving?")
                    continue
                if "UNDEFINED_PARAM_" in bucket_name:
                    bucket_name = bucket_name[len("UNDEFINED_PARAM_") :]

                bucket = cfmodel.Resources.get(bucket_name)
                if bucket and bucket.Properties.AccessControl == "PublicRead":
                    self.add_failure_to_result(
                        result,
                        self.REASON.format(logical_id),
                        resource_ids={logical_id},
                        resource_types={resource.Type},
                        context={
                            "config": self._config,
                            "extras": extras,
                            "logical_id": logical_id,
                            "resource": resource,
                            "bucket_name": bucket_name,
                        },
                    )
        return result
示例#12
0
    def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result:
        result = Result()
        for logical_id, resource in cfmodel.Resources.items():
            if isinstance(resource, IAMRole):
                # check AssumeRolePolicyDocument.
                if resource.Properties.AssumeRolePolicyDocument.allowed_actions_with(REGEX_WILDCARD_POLICY_ACTION):
                    self.add_failure_to_result(
                        result, self.REASON.format(logical_id, "AssumeRolePolicy"), resource_ids={logical_id},
                    )

                # check other policies of the IAM role.
                if resource.Properties.Policies:
                    for policy in resource.Properties.Policies:
                        if policy.PolicyDocument.allowed_actions_with(REGEX_WILDCARD_POLICY_ACTION):
                            self.add_failure_to_result(
                                result,
                                self.REASON.format(logical_id, f"{policy.PolicyName} policy"),
                                resource_ids={logical_id},
                            )

            # check AWS::IAM::ManagedPolicy.
            elif isinstance(resource, IAMManagedPolicy) and resource.Properties.PolicyDocument.allowed_actions_with(
                REGEX_WILDCARD_POLICY_ACTION
            ):
                self.add_failure_to_result(
                    result, self.REASON.format(logical_id, "AWS::IAM::ManagedPolicy"), resource_ids={logical_id},
                )
        return result
示例#13
0
 def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result:
     result = Result()
     for logical_id, resource in cfmodel.Resources.items():
         if isinstance(resource, IAMRole):
             self.check_managed_policies(result, logical_id, resource)
             self.check_inline_policies(result, logical_id, resource)
     return result
示例#14
0
    def test_with_templates(self):
        dir_path = os.path.dirname(os.path.realpath(__file__))

        test_templates = glob.glob(f"{dir_path}/test_templates/*.*")
        for template in test_templates:
            with open(template) as cf_script:
                cf_template = convert_json_or_yaml_to_dict(cf_script.read())

            config = Config(
                project_name=template, service_name=template, stack_name=template, rules=DEFAULT_RULES.keys()
            )

            # Scan result
            result = Result()

            rules = [DEFAULT_RULES.get(rule)(config, result) for rule in config.rules]
            processor = RuleProcessor(*rules)
            processor.process_cf_template(cf_template, config, result)

            # Use this to print the stack if there's an error
            if len(result.exceptions):
                print(template)
                traceback.print_tb(result.exceptions[0].__traceback__)

            no_resource_templates = ["vulgar_bad_syntax.yml", "rubbish.json"]

            if template.split("/")[-1] in no_resource_templates:
                assert len(result.exceptions) == 1
            else:
                assert len(result.exceptions) == 0
示例#15
0
 def invoke(self,
            cfmodel: CFModel,
            extras: Optional[Dict] = None) -> Result:
     result = Result()
     for logical_id, resource in cfmodel.Resources.items():
         for policy in resource.policy_documents:
             self._check_policy_document(result, logical_id,
                                         policy.policy_document,
                                         policy.name, extras)
         if isinstance(resource, IAMRole):
             self._check_policy_document(
                 result, logical_id,
                 resource.Properties.AssumeRolePolicyDocument, None, extras)
         elif isinstance(resource, KMSKey):
             self._check_policy_document(result, logical_id,
                                         resource.Properties.KeyPolicy,
                                         None, extras)
         elif isinstance(resource, GenericResource):
             if hasattr(resource, "Properties"):
                 policy_document = resource.Properties.get("PolicyDocument")
                 if policy_document:
                     self._check_policy_document(
                         result, logical_id,
                         PolicyDocument(**policy_document), None, extras)
     return result
示例#16
0
def test_remove_failures_from_whitelisted_actions_failure_no_actions_is_removed(
        mock_logger, mock_rule_to_action_whitelist):
    config = Config(
        stack_name="teststack",
        rules=["S3CrossAccountTrustRule"],
        rule_to_action_whitelist=mock_rule_to_action_whitelist,
    )

    result = Result()
    failure = Failure(
        rule="S3CrossAccountTrustRule",
        reason=
        "rolething has forbidden cross-account policy allow with 123456789 for an S3 bucket.",
        rule_mode=RuleMode.BLOCKING,
        risk_value=RuleRisk.HIGH,
        actions=set(),
        granularity=RuleGranularity.ACTION,
    )
    result.failed_rules = [failure]

    RuleProcessor.remove_failures_of_whitelisted_actions(config=config,
                                                         result=result)
    assert result.failed_rules == []
    mock_logger.assert_called_once_with(
        f"Failure with action granularity doesn't have actions: {failure}")
def test_with_invalid_role_managed_policy():
    role_props = {
        "AWSTemplateFormatVersion": "2010-09-09",
        "Resources": {
            "RootRole": {
                "Type": "AWS::IAM::Role",
                "Properties": {
                    "Path":
                    "/",
                    "ManagedPolicyArns":
                    ["arn:aws:iam::aws:policy/AdministratorAccess"]
                },
            }
        },
    }

    result = Result()
    rule = IAMRolesOverprivilegedRule(None, result)
    resources = pycfmodel.parse(role_props).resources
    rule.invoke(resources, [])

    assert not result.valid
    assert (
        result.failed_rules[0]["reason"] ==
        "Role RootRole has forbidden Managed Policy arn:aws:iam::aws:policy/AdministratorAccess"
    )
    assert result.failed_rules[0]["rule"] == "IAMRolesOverprivilegedRule"
示例#18
0
def test_report_format_is_the_one_expected(template_one_role):
    result = Result()
    rule = CrossAccountTrustRule(Config(aws_account_id="123456789"), result)
    rule.invoke(template_one_role)

    assert not result.valid
    assert result.failed_rules == [
        Failure(
            rule="CrossAccountTrustRule",
            reason=
            "RootRole has forbidden cross-account trust relationship with arn:aws:iam::123456789:root",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.MEDIUM,
            resource_ids={"RootRole"},
            actions=set(),
            granularity=RuleGranularity.RESOURCE,
        ),
        Failure(
            rule="CrossAccountTrustRule",
            reason=
            ("RootRole has forbidden cross-account trust relationship with arn:aws:iam::999999999:role/"
             "*****@*****.**"),
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.MEDIUM,
            resource_ids={"RootRole"},
            actions=set(),
            granularity=RuleGranularity.RESOURCE,
        ),
    ]
def test_failures_are_raised(bad_template):
    result = Result()
    rule = PartialWildcardPrincipalRule(None, result)
    rule.invoke(bad_template)

    assert result.valid
    assert len(result.failed_rules) == 0
    assert len(result.failed_monitored_rules) == 4
    assert result.failed_monitored_rules[
        0].rule == "PartialWildcardPrincipalRule"
    assert result.failed_monitored_rules[
        0].reason == "PolicyA contains an unknown principal: 123445"
    assert result.failed_monitored_rules[
        1].rule == "PartialWildcardPrincipalRule"
    assert (
        result.failed_monitored_rules[1].reason ==
        "PolicyA should not allow wildcard in principals or account-wide principals "
        "(principal: 'arn:aws:iam::123445:12345*')")
    assert result.failed_monitored_rules[
        2].rule == "PartialWildcardPrincipalRule"
    assert result.failed_monitored_rules[
        2].reason == "PolicyA contains an unknown principal: 123445"
    assert result.failed_monitored_rules[
        3].rule == "PartialWildcardPrincipalRule"
    assert (
        result.failed_monitored_rules[3].reason ==
        "PolicyA should not allow wildcard in principals or account-wide principals "
        "(principal: 'arn:aws:iam::123445:root')")
示例#20
0
 def invoke(self,
            cfmodel: CFModel,
            extras: Optional[Dict] = None) -> Result:
     result = Result()
     for logical_id, resource in cfmodel.Resources.items():
         if isinstance(resource, KMSKey):
             for statement in resource.Properties.KeyPolicy._statement_as_list(
             ):
                 if statement.Effect == "Allow" and statement.principals_with(
                         self.CONTAINS_WILDCARD_PATTERN):
                     for principal in statement.get_principal_list():
                         if self.CONTAINS_WILDCARD_PATTERN.match(principal):
                             if statement.Condition and statement.Condition.dict(
                             ):
                                 logger.warning(
                                     f"Not adding {type(self).__name__} failure in {logical_id} "
                                     f"because there are conditions: {statement.Condition}"
                                 )
                             else:
                                 self.add_failure_to_result(
                                     result,
                                     self.REASON.format(logical_id),
                                     resource_ids={logical_id},
                                     context={
                                         "config": self._config,
                                         "extras": extras,
                                         "logical_id": logical_id,
                                         "resource": resource,
                                         "statement": statement,
                                         "principal": principal,
                                     },
                                 )
     return result
示例#21
0
 def resource_invoke(self,
                     resource: SQSQueuePolicy,
                     logical_id: str,
                     extras: Optional[Dict] = None) -> Result:
     result = Result()
     if resource.Properties.PolicyDocument.allowed_principals_with(
             REGEX_HAS_STAR_OR_STAR_AFTER_COLON):
         for statement in resource.Properties.PolicyDocument.statement_as_list(
         ):
             if statement.Effect == "Allow" and statement.principals_with(
                     REGEX_HAS_STAR_OR_STAR_AFTER_COLON):
                 if statement.Condition and statement.Condition.dict():
                     # Ignoring condition checks since they will get reviewed in other rules and future improvements
                     pass
                 else:
                     self.add_failure_to_result(
                         result,
                         self.REASON.format(logical_id),
                         resource_ids={logical_id},
                         resource_types={resource.Type},
                         context={
                             "config": self._config,
                             "extras": extras,
                             "logical_id": logical_id,
                             "resource": resource,
                             "statement": statement,
                         },
                     )
     return result
示例#22
0
def test_remove_failures_from_whitelisted_resources_only_removes_resource_granularity(mock_rule_to_resource_whitelist):
    config = Config(
        stack_name="otherstack",
        rules=["S3CrossAccountTrustRule"],
        rule_to_resource_whitelist=mock_rule_to_resource_whitelist,
    )

    result = Result()
    failed_rules = [
        {
            "rule": "S3CrossAccountTrustRule",
            "reason": "rolething has forbidden cross-account policy allow with 123456789 for an S3 bucket.",
            "rule_mode": RuleMode.BLOCKING,
            "risk_value": RuleRisk.HIGH,
            "resource_ids": {"rolething"},
            "actions": None,
            "granularity": RuleGranularity.ACTION,
        },
        {
            "rule": "S3CrossAccountTrustRule",
            "reason": "anotherthing has forbidden cross-account policy allow with 123456789 for an S3 bucket.",
            "rule_mode": RuleMode.BLOCKING,
            "risk_value": RuleRisk.HIGH,
            "resource_ids": {"anotherthing"},
            "actions": None,
            "granularity": RuleGranularity.RESOURCE,
        }
    ]
    result.failed_rules = failed_rules

    RuleProcessor.remove_failures_of_whitelisted_resources(config=config, result=result)
    assert result.failed_rules == failed_rules
示例#23
0
    def invoke(self,
               cfmodel: CFModel,
               extras: Optional[Dict] = None) -> Result:
        result = Result()
        for logical_id, resource in cfmodel.Resources.items():
            if isinstance(resource,
                          (IAMManagedPolicy, IAMPolicy, S3BucketPolicy,
                           SNSTopicPolicy, SQSQueuePolicy)):
                self.check_for_wildcards(
                    result=result,
                    logical_id=logical_id,
                    resource=resource.Properties.PolicyDocument,
                    resource_type=resource.Type,
                    extras=extras,
                )
            elif isinstance(resource, (IAMRole, IAMUser)):
                if isinstance(resource, IAMRole):
                    self.check_for_wildcards(
                        result=result,
                        logical_id=logical_id,
                        resource=resource.Properties.AssumeRolePolicyDocument,
                        resource_type=resource.Type,
                        extras=extras,
                    )
                if resource.Properties and resource.Properties.Policies:
                    for policy in resource.Properties.Policies:
                        self.check_for_wildcards(
                            result=result,
                            logical_id=logical_id,
                            resource=policy.PolicyDocument,
                            resource_type=resource.Type,
                            extras=extras,
                        )

        return result
    def test_invalid_security_group_range(self):
        role_props = {
            "AWSTemplateFormatVersion": "2010-09-09",
            "Resources": {
                "RootRole": {
                    "Type": "AWS::EC2::SecurityGroup",
                    "Properties": {
                        'SecurityGroupIngress': [{
                            'CidrIp': "0.0.0.0/0",
                            'FromPort': 0,
                            'ToPort': 100
                        }]
                    }
                }
            }
        }

        result = Result()
        rule = SecurityGroupOpenToWorldRule(None, result)
        resources = parse(role_props).resources
        rule.invoke(resources)

        assert result.failed_rules[0][
            'reason'] == 'Ports 0 - 100 open in Security Group RootRole'
        assert result.failed_rules[0]['rule'] == 'SecurityGroupOpenToWorldRule'
示例#25
0
def test_action_whitelist_keeps_non_whitelisted_actions():
    whitelist_for_all_stacks = {"MockRule": {".*": {"s3:List"}}}
    config = Config(stack_name="abcd", rules=["MockRule"], rule_to_action_whitelist=whitelist_for_all_stacks)

    result = Result()
    failed_rules = [
        Failure(
            rule="MockRule",
            reason="MockRule is invalid for some actions",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            actions={"s3:ListBucket", "s3:GetBucket"},
            granularity=RuleGranularity.ACTION,
        )
    ]
    result.failed_rules = failed_rules

    RuleProcessor.remove_failures_of_whitelisted_actions(config=config, result=result)
    assert result.failed_rules == [
        Failure(
            rule="MockRule",
            reason="MockRule is invalid for some actions",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            actions={"s3:GetBucket"},
            granularity=RuleGranularity.ACTION,
        )
    ]
    def test_security_group_rules_as_refs(self):

        role_props = {
            "AWSTemplateFormatVersion": "2010-09-09",
            "Resources": {
                "RootRole": {
                    "Type": "AWS::EC2::SecurityGroup",
                    "Properties": {
                        'SecurityGroupIngress': [{
                            'CidrIp': {
                                "Ref": "MyParam"
                            },
                            'FromPort': 22,
                            'ToPort': 22
                        }]
                    }
                }
            }
        }

        result = Result()
        rule = SecurityGroupOpenToWorldRule(None, result)
        resources = parse(role_props).resources
        rule.invoke(resources)

        assert result.valid
        assert len(result.failed_rules) == 0
示例#27
0
 def process_cf_template(self,
                         cfmodel: CFModel,
                         config: Config,
                         extras: Optional[Dict] = None) -> Result:
     result = Result()
     for rule in self.rules:
         try:
             result += rule.invoke(cfmodel, extras)
         except Exception as other_exception:
             result.add_exception(other_exception)
             logger.exception(
                 "{} crashed with {} for project - {}, service - {}, stack - {}"
                 .format(
                     type(rule).__name__,
                     type(other_exception).__name__,
                     config.project_name,
                     config.service_name,
                     config.stack_name,
                 ))
             continue
     self.remove_failures_of_whitelisted_actions(config=config,
                                                 result=result)
     self.remove_failures_of_whitelisted_resources(config=config,
                                                   result=result)
     return result
    def test_security_group_type_slash0(self):
        role_props = {
            "AWSTemplateFormatVersion": "2010-09-09",
            "Resources": {
                "RootRole": {
                    "Type": "AWS::EC2::SecurityGroup",
                    "Properties": {
                        'SecurityGroupIngress': [{
                            'CidrIp': "0.0.0.0/0",
                            'FromPort': 22,
                            'ToPort': 22
                        }]
                    }
                }
            }
        }

        result = Result()
        rule = SecurityGroupOpenToWorldRule(None, result)
        resources = parse(role_props).resources
        rule.invoke(resources)

        assert not result.valid
        assert result.failed_rules[0][
            'reason'] == 'Port 22 open to the world in security group "RootRole"'
        assert result.failed_rules[0]['rule'] == 'SecurityGroupOpenToWorldRule'
    def invoke(self,
               cfmodel: CFModel,
               extras: Optional[Dict] = None) -> Result:
        result = Result()
        password_protected_cluster_ids = []
        instances_to_check = []

        for logical_id, resource in cfmodel.Resources.items():
            # flag insecure RDS Clusters.
            if resource.Type == "AWS::RDS::DBCluster":
                failure_added = self._failure_added(result, logical_id,
                                                    resource)
                if not failure_added:
                    password_protected_cluster_ids.append(logical_id)

            # keep track of RDS instances so they can be examined in the code below.
            elif resource.Type == "AWS::RDS::DBInstance":
                instances_to_check.append((logical_id, resource))

        # check each instance with the context of clusters.
        for logical_id, resource in instances_to_check:
            if resource.Properties.get("DBClusterIdentifier") and any(
                    cluster_id in resource.Properties.get(
                        "DBClusterIdentifier")
                    for cluster_id in password_protected_cluster_ids):
                continue

            self._failure_added(result, logical_id, resource)
        return result
示例#30
0
 def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result:
     result = Result()
     for logical_id, resource in cfmodel.Resources.items():
         if isinstance(resource, KMSKey):
             for statement in resource.Properties.KeyPolicy._statement_as_list():
                 filtered_principals = statement.principals_with(self.CONTAINS_WILDCARD_PATTERN)
                 if statement.Effect == "Allow" and filtered_principals:
                     for principal in filtered_principals:
                         if statement.Condition and statement.Condition.dict():
                             # Ignoring condition checks since they will get reviewed in other
                             # rules and future improvements
                             pass
                         else:
                             self.add_failure_to_result(
                                 result,
                                 self.REASON.format(logical_id),
                                 resource_ids={logical_id},
                                 context={
                                     "config": self._config,
                                     "extras": extras,
                                     "logical_id": logical_id,
                                     "resource": resource,
                                     "statement": statement,
                                     "principal": principal,
                                 },
                             )
     return result