def remove_failures_of_whitelisted_actions(config: Config, result: Result): if not result.failed_rules: return clean_failures = [] for failure in result.failed_rules: if failure.granularity != RuleGranularity.ACTION: clean_failures.append(failure) continue if not failure.actions: logger.warning(f"Failure with action granularity doesn't have actions: {failure}") continue whitelisted_actions = { action for action in failure.actions if any( [ re.match(whitelisted_action_regex, action) for whitelisted_action_regex in config.get_whitelisted_actions(failure.rule) ] ) } failure.actions = failure.actions - whitelisted_actions if failure.actions: clean_failures.append(failure) result.failed_rules = clean_failures
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 remove_failures_of_whitelisted_resources(config: Config, result: Result): if not result.failed_rules: return clean_failures = [] for failure in result.failed_rules: if failure.granularity != RuleGranularity.RESOURCE: clean_failures.append(failure) continue if not failure.resource_ids: logger.warning(f"Failure with resource granularity doesn't have resources: {failure}") continue whitelisted_resources = { resource for resource in failure.resource_ids if any( [ re.match(whitelisted_resource_regex, resource) for whitelisted_resource_regex in config.get_whitelisted_resources(failure.rule) ] ) } failure.resource_ids = failure.resource_ids - whitelisted_resources if failure.resource_ids: clean_failures.append(failure) result.failed_rules = clean_failures
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
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_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_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 = [ { "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, }, { "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 == [{ "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, }]
def test_result_valid_after_removing_failures(): result = Result() result.add_failure( rule="mock_rule", reason="mock_reason", rule_mode=RuleMode.BLOCKING, risk_value=RuleRisk.HIGH, granularity=RuleGranularity.STACK, ) # Result has a blocking failure, so it should be invalid assert result.valid is False result.failed_rules = [] # Result has no failures, so it should be valid assert result.valid is True
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_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_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, ) ]
def test_remove_failures_from_whitelisted_resources_failure_no_resources_is_removed(mock_logger, mock_rule_to_resource_whitelist): config = Config( stack_name="otherstack", rules=["S3CrossAccountTrustRule"], rule_to_resource_whitelist=mock_rule_to_resource_whitelist, ) result = Result() 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": None, "granularity": RuleGranularity.RESOURCE, } result.failed_rules = [failure] RuleProcessor.remove_failures_of_whitelisted_resources(config=config, result=result) assert result.failed_rules == [] mock_logger.assert_called_once_with(f"Failure with resource granularity doesn't have resources: {failure}")