def test_failures_are_raised_for_bad_instances_and_bad_clusters(
        bad_template_clusters_with_bad_instances):
    rule = HardcodedRDSPasswordRule(None)
    result = rule.invoke(bad_template_clusters_with_bad_instances)

    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "Default RDS Cluster password parameter (readable in plain-text) for BadCluster99.",
                risk_value=RuleRisk.MEDIUM,
                rule="HardcodedRDSPasswordRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"BadCluster99"},
                resource_types={"AWS::RDS::DBCluster"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "RDS Instance password parameter missing NoEcho for BadDb33.",
                risk_value=RuleRisk.MEDIUM,
                rule="HardcodedRDSPasswordRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"BadDb33"},
                resource_types={"AWS::RDS::DBInstance"},
            ),
        ],
    )
def test_failures_are_raised(bad_template):
    rule = S3BucketPolicyPrincipalRule(Config(aws_principals=["12345"]))
    result = rule.invoke(bad_template)

    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "S3 Bucket S3BucketPolicy policy has non-allowed principals 1234556",
                risk_value=RuleRisk.HIGH,
                rule="S3BucketPolicyPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"S3BucketPolicy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "S3 Bucket S3BucketPolicy policy has non-allowed principals 1234557",
                risk_value=RuleRisk.HIGH,
                rule="S3BucketPolicyPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"S3BucketPolicy"},
            ),
        ],
    )
def test_s3_bucket_with_wildcards(s3_bucket_with_wildcards):
    rule = S3BucketPolicyWildcardActionRule(None)
    result = rule.invoke(s3_bucket_with_wildcards)

    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "The S3BucketPolicy S3BucketPolicy should not allow a `*` action",
                risk_value=RuleRisk.MEDIUM,
                rule="S3BucketPolicyWildcardActionRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"S3BucketPolicy"},
                resource_types={"AWS::S3::BucketPolicy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "The S3BucketPolicy S3BucketPolicy2 should not allow a `*` action",
                risk_value=RuleRisk.MEDIUM,
                rule="S3BucketPolicyWildcardActionRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"S3BucketPolicy2"},
                resource_types={"AWS::S3::BucketPolicy"},
            ),
        ],
    )
def test_user_with_inline_policy_with_wildcard_resource_is_detected(
        user_with_wildcard_resource):
    rule = WildcardResourceRule(None)
    rule._config.stack_name = "not_allowed_stack"
    rule.all_cf_actions = set()
    result = rule.invoke(user_with_wildcard_resource)

    assert result.valid is False
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity="ACTION",
                reason=
                '"userWithInline" is using a wildcard resource in "somePolicy" for "s3:DeleteBucket"',
                risk_value="MEDIUM",
                rule="WildcardResourceRule",
                rule_mode="BLOCKING",
                actions={"s3:ListBucket", "s3:DeleteBucket"},
                resource_ids={"userWithInline"},
            ),
            Failure(
                granularity="ACTION",
                reason=
                '"userWithInline" is using a wildcard resource in "somePolicy" for "s3:ListBucket"',
                risk_value="MEDIUM",
                rule="WildcardResourceRule",
                rule_mode="BLOCKING",
                actions={"s3:ListBucket", "s3:DeleteBucket"},
                resource_ids={"userWithInline"},
            ),
        ],
    )
Example #5
0
def test_remove_debug_rules():
    original_failed_monitored_rules = [
        Failure(
            rule="a",
            reason="something",
            rule_mode=RuleMode.MONITOR,
            granularity=RuleGranularity.STACK,
            risk_value=RuleRisk.HIGH,
        ),
        Failure(
            rule="b",
            reason="something",
            rule_mode=RuleMode.DEBUG,
            granularity=RuleGranularity.STACK,
            risk_value=RuleRisk.MEDIUM,
        ),
        Failure(
            rule="c",
            reason="something",
            rule_mode=RuleMode.MONITOR,
            granularity=RuleGranularity.STACK,
            risk_value=RuleRisk.LOW,
        ),
    ]

    list_with_no_debug_rules = [original_failed_monitored_rules[0], original_failed_monitored_rules[2]]

    processed_list = RuleProcessor.remove_debug_rules(rules=original_failed_monitored_rules)
    assert list_with_no_debug_rules == processed_list
def test_s3_read_plus_list(s3_read_plus_list):
    rule = S3BucketPublicReadAclAndListStatementRule(None)
    result = rule.invoke(s3_read_plus_list)

    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason="S3 Bucket S3BucketPolicy should not have a public read acl and list bucket statement",
                risk_value=RuleRisk.MEDIUM,
                rule="S3BucketPublicReadAclAndListStatementRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"S3BucketPolicy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason="S3 Bucket S3BucketPolicy2 should not have a public read acl and list bucket statement",
                risk_value=RuleRisk.MEDIUM,
                rule="S3BucketPublicReadAclAndListStatementRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"S3BucketPolicy2"},
            ),
        ],
    )
Example #7
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 expected_result_two_roles():
    return [
        Failure(
            rule="CrossAccountTrustRule",
            reason=(
                "RootRoleOne has forbidden cross-account trust relationship with "
                "arn:aws:iam::999999999:role/[email protected]"
            ),
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.MEDIUM,
            resource_ids={"RootRoleOne"},
            actions=set(),
            granularity=RuleGranularity.RESOURCE,
        ),
        Failure(
            rule="CrossAccountTrustRule",
            reason=(
                "RootRoleTwo has forbidden cross-account trust relationship with "
                "arn:aws:iam::999999999:role/[email protected]"
            ),
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.MEDIUM,
            resource_ids={"RootRoleTwo"},
            actions=set(),
            granularity=RuleGranularity.RESOURCE,
        ),
    ]
Example #9
0
def test_failures_are_raised(bad_template):
    rule = GenericResourcePartialWildcardPrincipalRule(None)
    result = rule.invoke(bad_template)

    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "PolicyA should not allow wildcard in principals or account-wide principals (principal: 'arn:aws:iam::123445:12345*')",
                risk_value=RuleRisk.MEDIUM,
                rule="GenericResourcePartialWildcardPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"PolicyA"},
                resource_types={"AWS::IAM::Policy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "PolicyA should not allow wildcard in principals or account-wide principals (principal: 'arn:aws:iam::123445:root')",
                risk_value=RuleRisk.MEDIUM,
                rule="GenericResourcePartialWildcardPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"PolicyA"},
                resource_types={"AWS::IAM::Policy"},
            ),
        ],
    )
Example #10
0
def test_failures_for_correct_account_ids(intra_account_root_access):
    rule = GenericResourcePartialWildcardPrincipalRule(
        Config(aws_account_id="123456789012"))
    result = rule.invoke(intra_account_root_access)

    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "AccLoadBalancerAccessLogBucketPolicy should not allow wildcard in principals or account-wide principals (principal: 'arn:aws:iam::123456789012:root')",
                risk_value=RuleRisk.MEDIUM,
                rule="GenericResourcePartialWildcardPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"AccLoadBalancerAccessLogBucketPolicy"},
                resource_types={"AWS::S3::BucketPolicy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "AccLoadBalancerAccessLogBucketPolicy should not allow wildcard in principals or account-wide principals (principal: '987654321012')",
                risk_value=RuleRisk.MEDIUM,
                rule="GenericResourcePartialWildcardPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"AccLoadBalancerAccessLogBucketPolicy"},
                resource_types={"AWS::S3::BucketPolicy"},
            ),
        ],
    )
Example #11
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,
        )
    ]
Example #12
0
def test_failures_are_raised(bad_template):
    rule = EC2SecurityGroupIngressOpenToWorldRule(Config())
    result = rule.invoke(bad_template)

    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "Port(s) 46 open to public IPs: (11.0.0.0/8) in security group 'securityGroupIngress1'",
                risk_value=RuleRisk.MEDIUM,
                rule="EC2SecurityGroupIngressOpenToWorldRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"securityGroupIngress1"},
                resource_types={"AWS::EC2::SecurityGroupIngress"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "Port(s) 46 open to public IPs: (::/0) in security group 'securityGroupIngress2'",
                risk_value=RuleRisk.MEDIUM,
                rule="EC2SecurityGroupIngressOpenToWorldRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"securityGroupIngress2"},
                resource_types={"AWS::EC2::SecurityGroupIngress"},
            ),
        ],
    )
def test_failures_are_raised(bad_template):
    rule = GenericResourceWildcardPrincipalRule(None)
    result = rule.invoke(bad_template)

    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "PolicyA should not allow full wildcard '*', or wildcard in account ID like 'arn:aws:iam::*:12345' at 'somewhatrestricted:*'",
                risk_value=RuleRisk.MEDIUM,
                rule="GenericResourceWildcardPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"PolicyA"},
                resource_types={"AWS::IAM::Policy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "PolicyA should not allow full wildcard '*', or wildcard in account ID like 'arn:aws:iam::*:12345' at 'arn:aws:iam::*:12345'",
                risk_value=RuleRisk.MEDIUM,
                rule="GenericResourceWildcardPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"PolicyA"},
                resource_types={"AWS::IAM::Policy"},
            ),
        ],
    )
Example #14
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_sqs_policy_public(sqs_policy_public):
    rule = SQSQueuePolicyPublicRule(None)
    result = rule.invoke(sqs_policy_public)

    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "SQS Queue policy QueuePolicyPublic1 should not be public",
                risk_value=RuleRisk.HIGH,
                rule="SQSQueuePolicyPublicRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"QueuePolicyPublic1"},
                resource_types={"AWS::SQS::QueuePolicy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "SQS Queue policy QueuePolicyPublic2 should not be public",
                risk_value=RuleRisk.HIGH,
                rule="SQSQueuePolicyPublicRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"QueuePolicyPublic2"},
                resource_types={"AWS::SQS::QueuePolicy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "SQS Queue policy QueuePolicyPublic3 should not be public",
                risk_value=RuleRisk.HIGH,
                rule="SQSQueuePolicyPublicRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"QueuePolicyPublic3"},
                resource_types={"AWS::SQS::QueuePolicy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "SQS Queue policy QueuePolicyPublic4 should not be public",
                risk_value=RuleRisk.HIGH,
                rule="SQSQueuePolicyPublicRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"QueuePolicyPublic4"},
                resource_types={"AWS::SQS::QueuePolicy"},
            ),
        ],
    )
def test_sqs_queue_with_wildcards(sqs_queue_with_wildcards):
    rule = SQSQueuePolicyWildcardActionRule(None)
    result = rule.invoke(sqs_queue_with_wildcards)

    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "The SQSQueuePolicy mysqspolicy1 should not allow a `*` action",
                risk_value=RuleRisk.MEDIUM,
                rule="SQSQueuePolicyWildcardActionRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"mysqspolicy1"},
                resource_types={"AWS::SQS::QueuePolicy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "The SQSQueuePolicy mysqspolicy1b should not allow a `*` action",
                risk_value=RuleRisk.MEDIUM,
                rule="SQSQueuePolicyWildcardActionRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"mysqspolicy1b"},
                resource_types={"AWS::SQS::QueuePolicy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "The SQSQueuePolicy mysqspolicy1c should not allow a `*` action",
                risk_value=RuleRisk.MEDIUM,
                rule="SQSQueuePolicyWildcardActionRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"mysqspolicy1c"},
                resource_types={"AWS::SQS::QueuePolicy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "The SQSQueuePolicy mysqspolicy1d should not allow a `*` action",
                risk_value=RuleRisk.MEDIUM,
                rule="SQSQueuePolicyWildcardActionRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"mysqspolicy1d"},
                resource_types={"AWS::SQS::QueuePolicy"},
            ),
        ],
    )
Example #17
0
def test_failures_are_raised(bad_template):
    rule = GenericResourcePartialWildcardPrincipalRule(None)
    result = rule.invoke(bad_template)

    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "PolicyA should not allow wildcard, account-wide or root in resource-id like 'arn:aws:iam::12345:root' at 'arn:aws:iam::123445:12345*'",
                risk_value=RuleRisk.MEDIUM,
                rule="GenericResourcePartialWildcardPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"PolicyA"},
                resource_types={"AWS::IAM::Policy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "PolicyA should not allow wildcard, account-wide or root in resource-id like 'arn:aws:iam::12345:root' at 'arn:aws:iam::123445:root'",
                risk_value=RuleRisk.MEDIUM,
                rule="GenericResourcePartialWildcardPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"PolicyA"},
                resource_types={"AWS::IAM::Policy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "PolicyA should not allow wildcard, account-wide or root in resource-id like 'arn:aws:iam::12345:root' at '79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be'",
                risk_value=RuleRisk.MEDIUM,
                rule="GenericResourcePartialWildcardPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"PolicyA"},
                resource_types={"AWS::IAM::Policy"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "PolicyA should not allow wildcard, account-wide or root in resource-id like 'arn:aws:iam::12345:root' at 'eb2fe74dc7e8125d8f8fcae89d90e6dfdecabf896e1a69d55e949b009fd95a97'",
                risk_value=RuleRisk.MEDIUM,
                rule="GenericResourcePartialWildcardPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"PolicyA"},
                resource_types={"AWS::IAM::Policy"},
            ),
        ],
    )
def test_can_whitelist_resource_from_any_stack_if_granularity_is_resource():

    whitelist_for_all_stacks = {
        "S3CrossAccountTrustRule": {
            ".*": {"ProductionAccessTest"},
            "otherstack": {"rolething"}
        }
    }
    config = Config(stack_name="abcd",
                    rules=["S3CrossAccountTrustRule"],
                    rule_to_resource_whitelist=whitelist_for_all_stacks)

    result = Result()
    failed_rules = [
        Failure(
            rule="S3CrossAccountTrustRule",
            reason=
            "ProductionAccessTest has forbidden cross-account policy allow with 123456789 for an S3 bucket.",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            resource_ids={"ProductionAccessTest"},
            actions=None,
            granularity=RuleGranularity.RESOURCE,
        ),
        Failure(
            rule="S3CrossAccountTrustRule",
            reason=
            "This one isn't whitelisted because granularity is ACTION and not RESOURCE",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            resource_ids={"ProductionAccessTest"},
            actions=None,
            granularity=RuleGranularity.ACTION,
        ),
    ]
    result.failed_rules = failed_rules

    RuleProcessor.remove_failures_of_whitelisted_resources(config=config,
                                                           result=result)
    assert result.failed_rules == [
        Failure(
            rule="S3CrossAccountTrustRule",
            reason=
            "This one isn't whitelisted because granularity is ACTION and not RESOURCE",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            resource_ids={"ProductionAccessTest"},
            actions=None,
            granularity=RuleGranularity.ACTION,
        )
    ]
Example #19
0
def test_non_matching_filters_are_reported_normally(bad_template):
    mock_config = Config(
        rules=["EC2SecurityGroupIngressOpenToWorldRule"],
        aws_account_id="123456789",
        stack_name="mockstack",
        rules_filters=[
            Filter(
                rule_mode=RuleMode.ALLOWED,
                eval={"eq": [{
                    "ref": "config.stack_name"
                }, "anotherstack"]},
                rules={"EC2SecurityGroupIngressOpenToWorldRule"},
            )
        ],
    )
    rules = [
        DEFAULT_RULES.get(rule)(mock_config) for rule in mock_config.rules
    ]
    processor = RuleProcessor(*rules)
    result = processor.process_cf_template(bad_template, mock_config)
    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "Port(s) 46 open to public IPs: (11.0.0.0/8) in security group 'securityGroupIngress1'",
                risk_value=RuleRisk.MEDIUM,
                rule="EC2SecurityGroupIngressOpenToWorldRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"securityGroupIngress1"},
                resource_types={"AWS::EC2::SecurityGroupIngress"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "Port(s) 46 open to public IPs: (::/0) in security group 'securityGroupIngress2'",
                risk_value=RuleRisk.MEDIUM,
                rule="EC2SecurityGroupIngressOpenToWorldRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"securityGroupIngress2"},
                resource_types={"AWS::EC2::SecurityGroupIngress"},
            ),
        ],
    )
Example #20
0
 def add_warning_to_result(
     self,
     result: Result,
     reason: str,
     granularity: Optional[RuleGranularity] = None,
     resource_ids: Optional[Set] = None,
     actions: Optional[Set] = None,
     risk_value: Optional[RuleRisk] = None,
     rule_mode: Optional[RuleMode] = None,
     context: Optional[Dict] = None,
 ):
     rule_mode = rule_mode or self.rule_mode
     risk_value = risk_value or self.risk_value
     for fltr in self.rule_config.filters:
         if fltr(**context):
             risk_value = fltr.risk_value or risk_value
             rule_mode = fltr.rule_mode or rule_mode
     if rule_mode not in (RuleMode.DISABLED, RuleMode.WHITELISTED):
         warning = Failure(
             rule=type(self).__name__,
             reason=reason,
             granularity=granularity or self.GRANULARITY,
             resource_ids=resource_ids,
             actions=actions,
             risk_value=risk_value,
             rule_mode=rule_mode,
         )
         result.add_warning(warning)
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}")
Example #22
0
def test_policy_document_with_condition_is_ignored(
        iam_policy_with_wildcard_resource_and_wildcard_action_and_condition):
    rule = WildcardResourceRule(None)
    rule._config.stack_name = "stack3"
    rule.all_cf_actions = set()
    result = rule.invoke(
        iam_policy_with_wildcard_resource_and_wildcard_action_and_condition)

    assert result.valid
    assert result.failed_monitored_rules == []
    assert compare_lists_of_failures(
        result.warnings,
        [
            Failure(
                granularity="ACTION",
                reason=
                '"RolePolicy" is using a wildcard resource in "root" allowing all actions',
                risk_value="MEDIUM",
                rule="WildcardResourceRule",
                rule_mode="BLOCKING",
                actions={"*"},
                resource_ids={"RolePolicy"},
            )
        ],
    )
def test_policy_document_with_wildcard_resource_and_wilcard_action_without_policy_name_is_detected(
    iam_policy_with_wildcard_resource_and_wilcard_action_without_policy_name,
):
    rule = WildcardResourceRule(None)
    rule._config.stack_name = "stack3"
    rule.all_cf_actions = set()
    result = rule.invoke(
        iam_policy_with_wildcard_resource_and_wilcard_action_without_policy_name
    )

    assert result.valid is False
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity="ACTION",
                reason=
                '"RolePolicy" is using a wildcard resource allowing all actions',
                risk_value="MEDIUM",
                rule="WildcardResourceRule",
                rule_mode="BLOCKING",
                actions={"*"},
                resource_ids={"RolePolicy"},
            )
        ],
    )
def test_generic_cross_account_for_opensearch_domain_different_principals(
        principal):
    rule = GenericCrossAccountTrustRule(
        Config(aws_account_id="123456789", aws_principals=["999999999"]))
    model = get_cfmodel_from(
        "rules/CrossAccountTrustRule/opensearch_domain_basic.yml").resolve(
            extra_params={"Principal": principal})
    result = rule.invoke(model)
    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                f"TestDomain has forbidden cross-account with {principal}",
                risk_value=RuleRisk.MEDIUM,
                rule="GenericCrossAccountTrustRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"TestDomain"},
                resource_types={"AWS::OpenSearchService::Domain"},
            )
        ],
    )
def test_remove_failures_from_whitelisted_actions_only_removes_action_granularity(
        mock_rule_to_action_whitelist):
    config = Config(
        stack_name="teststack",
        rules=["S3CrossAccountTrustRule"],
        rule_to_action_whitelist=mock_rule_to_action_whitelist,
    )

    result = Result()
    failed_rules = [
        Failure(
            rule="WildcardResourceRule",
            reason=
            "rolething is using a wildcard resource in BucketAccessPolicy",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            resource_ids={"BucketAccessPolicy"},
            actions={"s3:Get*"},
            granularity=RuleGranularity.ACTION,
        ),
        Failure(
            rule="WildcardResourceRule",
            reason=
            "rolething is using a wildcard resource in BucketAccessPolicy",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            resource_ids=set(),
            actions=set(),
            granularity=RuleGranularity.STACK,
        ),
    ]
    result.failed_rules = failed_rules

    RuleProcessor.remove_failures_of_whitelisted_actions(config=config,
                                                         result=result)
    assert result.failed_rules == [
        Failure(
            rule="WildcardResourceRule",
            reason=
            "rolething is using a wildcard resource in BucketAccessPolicy",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            resource_ids=set(),
            actions=set(),
            granularity=RuleGranularity.STACK,
        )
    ]
def test_can_whitelist_action_from_any_stack_if_granularity_is_action():

    whitelist_for_all_stacks = {
        "S3CrossAccountTrustRule": {
            ".*": {"s3:ListBucket"}
        }
    }
    config = Config(stack_name="abcd",
                    rules=["S3CrossAccountTrustRule"],
                    rule_to_action_whitelist=whitelist_for_all_stacks)

    result = Result()
    failed_rules = [
        Failure(
            rule="S3CrossAccountTrustRule",
            reason=
            "ProductionAccessTest has forbidden cross-account policy allow with 123456789 for an S3 bucket.",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            actions={"s3:ListBucket"},
            granularity=RuleGranularity.ACTION,
        ),
        Failure(
            rule="S3CrossAccountTrustRule",
            reason=
            "This one isn't whitelisted because granularity is STACK and not ACTION",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            actions=set(),
            granularity=RuleGranularity.STACK,
        ),
    ]
    result.failed_rules = failed_rules

    RuleProcessor.remove_failures_of_whitelisted_actions(config=config,
                                                         result=result)
    assert result.failed_rules == [
        Failure(
            rule="S3CrossAccountTrustRule",
            reason=
            "This one isn't whitelisted because granularity is STACK and not ACTION",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            actions=set(),
            granularity=RuleGranularity.STACK,
        )
    ]
def test_remove_failures_from_whitelisted_actions_uses_whitelist(
        mock_rule_to_action_whitelist):

    config = Config(stack_name="teststack",
                    rules=["WildcardResourceRule"],
                    rule_to_action_whitelist=mock_rule_to_action_whitelist)

    result = Result()
    result.failed_rules = [
        Failure(
            rule="WildcardResourceRule",
            reason=
            "rolething is using a wildcard resource in BucketAccessPolicy",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            resource_ids={"BucketAccessPolicy"},
            actions={"s3:Get*"},
            granularity=RuleGranularity.ACTION,
        ),
        Failure(
            rule="WildcardResourceRule",
            reason=
            "rolething is using a wildcard resource in DynamoAccessPolicy",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            resource_ids={"DynamoAccessPolicy"},
            actions={"dynamodb:Get"},
            granularity=RuleGranularity.ACTION,
        ),
    ]

    RuleProcessor.remove_failures_of_whitelisted_actions(config=config,
                                                         result=result)
    assert result.failed_rules == [
        Failure(
            rule="WildcardResourceRule",
            reason=
            "rolething is using a wildcard resource in DynamoAccessPolicy",
            rule_mode=RuleMode.BLOCKING,
            risk_value=RuleRisk.HIGH,
            resource_ids={"DynamoAccessPolicy"},
            actions={"dynamodb:Get"},
            granularity=RuleGranularity.ACTION,
        )
    ]
Example #28
0
def test_result_addition():
    failure1 = Failure(
        granularity=RuleGranularity.STACK,
        reason="reason1",
        risk_value=RuleRisk.HIGH,
        rule="rule1",
        rule_mode=RuleMode.BLOCKING,
    )
    failure2 = Failure(
        granularity=RuleGranularity.STACK,
        reason="reason2",
        risk_value=RuleRisk.HIGH,
        rule="rule2",
        rule_mode=RuleMode.BLOCKING,
    )
    result1 = Result(failures=[failure1])
    result2 = Result(failures=[failure2])
    assert result1 + result2 == Result(failures=[failure1, failure2])
Example #29
0
def test_load_filters_work_with_several_rules(template_two_roles_dict,
                                              test_files_location):
    config = Config(
        rules=["CrossAccountTrustRule", "PartialWildcardPrincipalRule"],
        aws_account_id="123456789",
        stack_name="mockstack",
    )
    config.load_rules_config_file(
        open(
            f"{test_files_location}/config/rules_config_CrossAccountTrustRule.py"
        ))
    config.add_filters_from_dir(f"{test_files_location}/filters")
    rules = [DEFAULT_RULES.get(rule)(config) for rule in config.rules]
    processor = RuleProcessor(*rules)
    result = processor.process_cf_template(template_two_roles_dict, config)

    assert not result.valid
    assert compare_lists_of_failures(
        result.failures,
        [
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "RootRoleTwo has forbidden cross-account trust relationship with arn:aws:iam::999999999:role/[email protected]",
                risk_value=RuleRisk.MEDIUM,
                rule="CrossAccountTrustRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"RootRoleTwo"},
                resource_types={"AWS::IAM::Role"},
            ),
            Failure(
                granularity=RuleGranularity.RESOURCE,
                reason=
                "RootRoleTwo should not allow wildcard, account-wide or root in resource-id like 'arn:aws:iam::12345:root' at 'arn:aws:iam::123456789:root'",
                risk_value=RuleRisk.MEDIUM,
                rule="PartialWildcardPrincipalRule",
                rule_mode=RuleMode.BLOCKING,
                actions=None,
                resource_ids={"RootRoleTwo"},
                resource_types={"AWS::IAM::Role"},
            ),
        ],
    )
Example #30
0
def test_result_addition():
    failure1 = Failure(
        granularity=RuleGranularity.STACK,
        reason="reason1",
        risk_value="risk1",
        rule="rule1",
        rule_mode="mode1",
    )
    failure2 = Failure(
        granularity=RuleGranularity.STACK,
        reason="reason2",
        risk_value="risk2",
        rule="rule2",
        rule_mode="mode2",
    )
    monitored_failure1 = Failure(
        granularity=RuleGranularity.RESOURCE,
        reason="reason1",
        risk_value="risk1",
        rule="rule1",
        rule_mode="mode1",
    )
    monitored_failure2 = Failure(
        granularity=RuleGranularity.RESOURCE,
        reason="reason2",
        risk_value="risk2",
        rule="rule2",
        rule_mode="mode2",
    )
    result1 = Result(failed_rules=[failure1],
                     failed_monitored_rules=[monitored_failure1])
    result2 = Result(failed_rules=[failure2],
                     failed_monitored_rules=[monitored_failure2])
    assert result1 + result2 == Result(
        failed_rules=[failure1, failure2],
        failed_monitored_rules=[monitored_failure1, monitored_failure2])