def test_opensearch_domain_with_different_principals_in_rule_config( template, is_valid, failures): rule = OpenSearchDomainCrossAccountTrustRule( Config(aws_account_id="123456789", aws_principals=["999999999"])) result = rule.invoke(template) assert result.valid == is_valid assert compare_lists_of_failures(result.failures, failures)
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"}, ), ], )
def test_rule_supports_filter_config(bad_template_clusters_with_bad_instances, default_allow_all_config): rule = HardcodedRDSPasswordRule(default_allow_all_config) result = rule.invoke(bad_template_clusters_with_bad_instances) assert result.valid assert compare_lists_of_failures(result.failures, [])
def test_generic_cross_account_rule_for_resources_with_set_principals( template, is_valid, failures): rule = GenericCrossAccountTrustRule( Config(aws_account_id="123456789", aws_principals=["999999999"])) result = rule.invoke(template) assert result.valid == is_valid assert compare_lists_of_failures(result.failures, failures)
def test_rule_supports_filter_config(bad_template_no_configuration, default_allow_all_config): rule = S3LifecycleConfigurationRule(default_allow_all_config) result = rule.invoke(bad_template_no_configuration) assert result.valid assert compare_lists_of_failures(result.failures, [])
def test_s3_bucket_cross_account_for_current_account_with_generic( s3_bucket_cross_account): rule = GenericCrossAccountTrustRule(Config(aws_account_id="987654321")) result = rule.invoke(s3_bucket_cross_account) assert result.valid assert compare_lists_of_failures(result.failures, [])
def test_generic_rule_supports_filter_config( s3_bucket_cross_account_and_normal, default_allow_all_config): rule = GenericCrossAccountTrustRule(default_allow_all_config) result = rule.invoke(s3_bucket_cross_account_and_normal) assert result.valid assert compare_lists_of_failures(result.failures, [])
def test_rule_supports_filter_config(invalid_role_managed_policy, default_allow_all_config): rule = IAMRolesOverprivilegedRule(default_allow_all_config) result = rule.invoke(invalid_role_managed_policy) assert result.valid assert compare_lists_of_failures(result.failures, [])
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_rule_supports_filter_config(s3_read_plus_list, default_allow_all_config): rule = S3BucketPublicReadAclAndListStatementRule(default_allow_all_config) result = rule.invoke(s3_read_plus_list) assert result.valid assert compare_lists_of_failures(result.failures, [])
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_rule_supports_filter_config(privilege_escalation_role_cf, default_allow_all_config): rule = PrivilegeEscalationRule(default_allow_all_config) result = rule.invoke(privilege_escalation_role_cf) assert result.valid assert compare_lists_of_failures(result.failures, [])
def test_valid_privilege_escalation_on_s3_bucket_policy( valid_privilege_escalation_on_s3_bucket_policy): rule = PrivilegeEscalationRule(None) result = rule.invoke(valid_privilege_escalation_on_s3_bucket_policy) assert result.valid assert compare_lists_of_failures(result.failures, [])
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_rule_supports_filter_config(sns_topic_with_wildcards, default_allow_all_config): rule = SNSTopicPolicyWildcardActionRule(default_allow_all_config) result = rule.invoke(sns_topic_with_wildcards) assert result.valid assert compare_lists_of_failures(result.failures, [])
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"}, ), ], )
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_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_s3_bucket_cross_account_from_aws_service_with_generic( s3_bucket_cross_account_from_aws_service): rule = GenericCrossAccountTrustRule(Config(aws_account_id="123456789")) result = rule.invoke(s3_bucket_cross_account_from_aws_service) assert result.valid assert compare_lists_of_failures(result.failures, [])
def test_valid_iam_role_no_errors( iam_managed_policy_good_template_with_allow_and_deny): rule = IAMRoleWildcardActionOnPolicyRule(None) result = rule.invoke(iam_managed_policy_good_template_with_allow_and_deny) assert result.valid assert compare_lists_of_failures(result.failures, [])
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_rule_supports_filter_config(iam_managed_policy_bad_template, default_allow_all_config): rule = IAMRoleWildcardActionOnPolicyRule(default_allow_all_config) result = rule.invoke(iam_managed_policy_bad_template) assert result.valid assert compare_lists_of_failures(result.failures, [])
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"}, ), ], )
def test_rule_supports_filter_config(sqs_policy_not_principal, default_allow_all_config): rule = SQSQueuePolicyNotPrincipalRule(default_allow_all_config) result = rule.invoke(sqs_policy_not_principal) assert result.valid assert compare_lists_of_failures(result.failures, [])
def test_rule_supports_filter_config(bad_template, default_allow_all_config): rule = GenericResourcePartialWildcardPrincipalRule( default_allow_all_config) result = rule.invoke(bad_template) assert result.valid assert compare_lists_of_failures(result.failures, [])
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"}, ), ], )
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"}, ), ], )
def test_rule_supports_filter_config(sqs_policy_public, default_allow_all_config): rule = SQSQueuePolicyPublicRule(default_allow_all_config) result = rule.invoke(sqs_policy_public) assert result.valid assert compare_lists_of_failures(result.failures, [])
def test_failures_are_raised_for_instances(bad_template_instances): rule = HardcodedRDSPasswordRule(None) result = rule.invoke(bad_template_instances) assert not result.valid assert compare_lists_of_failures( result.failures, [ Failure( granularity=RuleGranularity.RESOURCE, reason= "RDS Instance password parameter missing NoEcho for BadDb3.", risk_value=RuleRisk.MEDIUM, rule="HardcodedRDSPasswordRule", rule_mode=RuleMode.BLOCKING, actions=None, resource_ids={"BadDb3"}, resource_types={"AWS::RDS::DBInstance"}, ), Failure( granularity=RuleGranularity.RESOURCE, reason= "Default RDS Instance password parameter (readable in plain-text) for BadDb5.", risk_value=RuleRisk.MEDIUM, rule="HardcodedRDSPasswordRule", rule_mode=RuleMode.BLOCKING, actions=None, resource_ids={"BadDb5"}, resource_types={"AWS::RDS::DBInstance"}, ), ], )
def test_elasticsearch_domain_cross_account_rule_with_set_principals( template, is_valid, failures): rule = ElasticsearchDomainCrossAccountTrustRule( Config(aws_account_id="123456789", aws_principals=["999999999"])) result = rule.invoke(template) assert result.valid == is_valid assert compare_lists_of_failures(result.failures, failures)