diff --git a/prowler/providers/aws/lib/policy_condition_parser/__init__.py b/prowler/providers/aws/lib/policy_condition_parser/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/prowler/providers/aws/lib/policy_condition_parser/policy_condition_parser.py b/prowler/providers/aws/lib/policy_condition_parser/policy_condition_parser.py deleted file mode 100644 index 3d313a1f71..0000000000 --- a/prowler/providers/aws/lib/policy_condition_parser/policy_condition_parser.py +++ /dev/null @@ -1,157 +0,0 @@ -def is_condition_block_restrictive( - condition_statement: dict, - source_account: str, - is_cross_account_allowed=False, -): - """ - is_condition_block_restrictive parses the IAM Condition policy block and, by default, returns True if the source_account passed as argument is within, False if not. - - If argument is_cross_account_allowed is True it tests if the Condition block includes any of the operators allowlisted returning True if does, False if not. - - - @param condition_statement: dict with an IAM Condition block, e.g.: - { - "StringLike": { - "AWS:SourceAccount": 111122223333 - } - } - - @param source_account: str with a 12-digit AWS Account number, e.g.: 111122223333 - - @param is_cross_account_allowed: bool to allow cross-account access, e.g.: True - - """ - is_condition_valid = False - - # The conditions must be defined in lowercase since the context key names are not case-sensitive. - # For example, including the aws:SourceAccount context key is equivalent to testing for AWS:SourceAccount - # https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html - valid_condition_options = { - "StringEquals": [ - "aws:sourceaccount", - "aws:sourceowner", - "s3:resourceaccount", - "aws:principalaccount", - "aws:resourceaccount", - "aws:sourcearn", - "aws:sourcevpc", - "aws:sourcevpce", - ], - "StringLike": [ - "aws:sourceaccount", - "aws:sourceowner", - "aws:sourcearn", - "aws:principalarn", - "aws:resourceaccount", - "aws:principalaccount", - "aws:sourcevpc", - "aws:sourcevpce", - ], - "ArnLike": ["aws:sourcearn", "aws:principalarn"], - "ArnEquals": ["aws:sourcearn", "aws:principalarn"], - } - - for condition_operator, condition_operator_key in valid_condition_options.items(): - if condition_operator in condition_statement: - for value in condition_operator_key: - # We need to transform the condition_statement into lowercase - condition_statement[condition_operator] = { - k.lower(): v - for k, v in condition_statement[condition_operator].items() - } - - if value in condition_statement[condition_operator]: - # values are a list - if isinstance( - condition_statement[condition_operator][value], - list, - ): - is_condition_key_restrictive = True - # if cross account is not allowed check for each condition block looking for accounts - # different than default - if not is_cross_account_allowed: - # if there is an arn/account without the source account -> we do not consider it safe - # here by default we assume is true and look for false entries - for item in condition_statement[condition_operator][value]: - if source_account not in item: - is_condition_key_restrictive = False - break - - if is_condition_key_restrictive: - is_condition_valid = True - - # value is a string - elif isinstance( - condition_statement[condition_operator][value], - str, - ): - if is_cross_account_allowed: - is_condition_valid = True - else: - if ( - source_account - in condition_statement[condition_operator][value] - ): - is_condition_valid = True - - return is_condition_valid - - -def is_condition_block_restrictive_organization( - condition_statement: dict, -): - """ - is_condition_block_restrictive_organization parses the IAM Condition policy block and returns True if the condition_statement is restrictive for the organization, False if not. - - @param condition_statement: dict with an IAM Condition block, e.g.: - { - "StringLike": { - "AWS:PrincipalOrgID": "o-111122223333" - } - } - - """ - is_condition_valid = False - - # The conditions must be defined in lowercase since the context key names are not case-sensitive. - # For example, including the aws:PrincipalOrgID context key is equivalent to testing for AWS:PrincipalOrgID - # https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html - valid_condition_options = { - "StringEquals": [ - "aws:principalorgid", - ], - "StringLike": [ - "aws:principalorgid", - ], - } - - for condition_operator, condition_operator_key in valid_condition_options.items(): - if condition_operator in condition_statement: - for value in condition_operator_key: - # We need to transform the condition_statement into lowercase - condition_statement[condition_operator] = { - k.lower(): v - for k, v in condition_statement[condition_operator].items() - } - - if value in condition_statement[condition_operator]: - # values are a list - if isinstance( - condition_statement[condition_operator][value], - list, - ): - is_condition_valid = True - for item in condition_statement[condition_operator][value]: - if item == "*": - is_condition_valid = False - break - - # value is a string - elif isinstance( - condition_statement[condition_operator][value], - str, - ): - if "*" not in condition_statement[condition_operator][value]: - is_condition_valid = True - - return is_condition_valid diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible.py b/prowler/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible.py index 20c6526b92..778c44be93 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible.py +++ b/prowler/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible.py @@ -1,5 +1,6 @@ from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.awslambda.awslambda_client import awslambda_client +from prowler.providers.aws.services.iam.lib.policy import is_policy_public class awslambda_function_not_publicly_accessible(Check): @@ -14,37 +15,11 @@ class awslambda_function_not_publicly_accessible(Check): report.status = "PASS" report.status_extended = f"Lambda function {function.name} has a policy resource-based policy not public." - - public_access = False - if function.policy: - for statement in function.policy["Statement"]: - # Only check allow statements - if statement["Effect"] == "Allow" and ( - "*" in statement["Principal"] - or ( - isinstance(statement["Principal"], dict) - and ( - "*" in statement["Principal"].get("AWS", "") - or "*" - in statement["Principal"].get("CanonicalUser", "") - or ( # Check if function can be invoked by other AWS services - ( - ".amazonaws.com" - in statement["Principal"].get("Service", "") - ) - and ( - "*" in statement.get("Action", "") - or "InvokeFunction" - in statement.get("Action", "") - ) - ) - ) - ) - ): - public_access = True - break - - if public_access: + if is_policy_public( + function.policy, + awslambda_client.audited_account, + is_cross_account_allowed=True, + ): report.status = "FAIL" report.status_extended = f"Lambda function {function.name} has a policy resource-based policy with public access." diff --git a/prowler/providers/aws/services/dynamodb/dynamodb_table_cross_account_access/dynamodb_table_cross_account_access.py b/prowler/providers/aws/services/dynamodb/dynamodb_table_cross_account_access/dynamodb_table_cross_account_access.py index 4f176dcc59..3f47461cd9 100644 --- a/prowler/providers/aws/services/dynamodb/dynamodb_table_cross_account_access/dynamodb_table_cross_account_access.py +++ b/prowler/providers/aws/services/dynamodb/dynamodb_table_cross_account_access/dynamodb_table_cross_account_access.py @@ -1,8 +1,6 @@ from prowler.lib.check.models import Check, Check_Report_AWS -from prowler.providers.aws.lib.policy_condition_parser.policy_condition_parser import ( - is_condition_block_restrictive, -) from prowler.providers.aws.services.dynamodb.dynamodb_client import dynamodb_client +from prowler.providers.aws.services.iam.lib.policy import is_policy_public class dynamodb_table_cross_account_access(Check): @@ -20,36 +18,10 @@ class dynamodb_table_cross_account_access(Check): ) if table.policy: report.status_extended = f"DynamoDB table {table.name} has a resource-based policy but is not cross account." - cross_account_access = False - policy_statements = table.policy["Statement"] - if isinstance( - policy_statements, dict - ): # Normalize single statement to list - policy_statements = [policy_statements] - for statement in policy_statements: - if not cross_account_access: - if statement["Effect"] == "Allow": - if "AWS" in statement["Principal"]: - principals = statement["Principal"]["AWS"] - if not isinstance(principals, list): - principals = [principals] - else: - principals = [statement["Principal"]] - for aws_account in principals: - if ( - dynamodb_client.audited_account not in aws_account - or "*" == aws_account - ): - cross_account_access = True - # Check if the condition block is restrictive - conditions = statement.get("Condition", {}) - if is_condition_block_restrictive( - conditions, dynamodb_client.audited_account - ): - cross_account_access = False - else: - break - if cross_account_access: + if is_policy_public( + table.policy, + source_account=dynamodb_client.audited_account, + ): report.status = "FAIL" report.status_extended = f"DynamoDB table {table.name} has a resource-based policy allowing cross account access." findings.append(report) diff --git a/prowler/providers/aws/services/ecr/ecr_repositories_not_publicly_accessible/ecr_repositories_not_publicly_accessible.py b/prowler/providers/aws/services/ecr/ecr_repositories_not_publicly_accessible/ecr_repositories_not_publicly_accessible.py index 18f3fb9472..a54e296387 100644 --- a/prowler/providers/aws/services/ecr/ecr_repositories_not_publicly_accessible/ecr_repositories_not_publicly_accessible.py +++ b/prowler/providers/aws/services/ecr/ecr_repositories_not_publicly_accessible/ecr_repositories_not_publicly_accessible.py @@ -1,5 +1,6 @@ from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.ecr.ecr_client import ecr_client +from prowler.providers.aws.services.iam.lib.policy import is_policy_public class ecr_repositories_not_publicly_accessible(Check): @@ -16,16 +17,9 @@ class ecr_repositories_not_publicly_accessible(Check): report.status_extended = ( f"Repository {repository.name} is not publicly accesible." ) - if repository.policy: - for statement in repository.policy["Statement"]: - if statement["Effect"] == "Allow": - if "*" in statement["Principal"] or ( - "AWS" in statement["Principal"] - and "*" in statement["Principal"]["AWS"] - ): - report.status = "FAIL" - report.status_extended = f"Repository {repository.name} policy may allow anonymous users to perform actions (Principal: '*')." - break + if is_policy_public(repository.policy): + report.status = "FAIL" + report.status_extended = f"Repository {repository.name} policy may allow anonymous users to perform actions (Principal: '*')." findings.append(report) diff --git a/prowler/providers/aws/services/efs/efs_not_publicly_accessible/efs_not_publicly_accessible.py b/prowler/providers/aws/services/efs/efs_not_publicly_accessible/efs_not_publicly_accessible.py index 98c348e139..73d89b938e 100644 --- a/prowler/providers/aws/services/efs/efs_not_publicly_accessible/efs_not_publicly_accessible.py +++ b/prowler/providers/aws/services/efs/efs_not_publicly_accessible/efs_not_publicly_accessible.py @@ -1,6 +1,6 @@ from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.efs.efs_client import efs_client -from prowler.providers.aws.services.efs.lib.lib import is_public_access_allowed +from prowler.providers.aws.services.iam.lib.policy import is_policy_public class efs_not_publicly_accessible(Check): @@ -17,13 +17,14 @@ class efs_not_publicly_accessible(Check): if not fs.policy: report.status = "FAIL" report.status_extended = f"EFS {fs.id} doesn't have any policy which means it grants full access to any client within the VPC." - else: - for statement in fs.policy.get("Statement", []): - if statement.get("Effect") == "Allow" and is_public_access_allowed( - statement - ): - report.status = "FAIL" - report.status_extended = f"EFS {fs.id} has a policy which allows access to any client within the VPC." - break + elif is_policy_public(fs.policy) and any( + statement.get("Condition", {}) + .get("Bool", {}) + .get("elasticfilesystem:AccessedViaMountTarget", "false") + != "true" + for statement in fs.policy.get("Statement", []) + ): + report.status = "FAIL" + report.status_extended = f"EFS {fs.id} has a policy which allows access to any client within the VPC." findings.append(report) return findings diff --git a/prowler/providers/aws/services/efs/lib/__init__.py b/prowler/providers/aws/services/efs/lib/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/prowler/providers/aws/services/efs/lib/lib.py b/prowler/providers/aws/services/efs/lib/lib.py deleted file mode 100644 index 2d310fc369..0000000000 --- a/prowler/providers/aws/services/efs/lib/lib.py +++ /dev/null @@ -1,45 +0,0 @@ -def is_public_access_allowed(statement): - """ - Check if the statement allows public access - Args: - statement: dict: Statement from the policy - Returns: - bool: True if the statement allows public access, False otherwise - """ - principal = statement.get("Principal") - if principal == "*" or (isinstance(principal, dict) and "*" in principal.values()): - return not has_secure_conditions(statement) - return False - - -def has_secure_conditions(statement): - """ - Check if the statement has secure conditions - Args: - statement: dict: Statement from the policy - Returns: - bool: True if the statement has secure conditions, False otherwise - """ - conditions = statement.get("Condition", {}) - allowed_conditions = { - "aws:SourceArn", - "aws:SourceVpc", - "aws:SourceVpce", - "aws:SourceOwner", - "aws:SourceAccount", - } - if ( - "Bool" in conditions - and conditions["Bool"].get("elasticfilesystem:AccessedViaMountTarget") == "true" - ): - return True - - # Check for conditions with nested keys - for _, conditions_dict in conditions.items(): - for key, value in conditions_dict.items(): - if isinstance(value, dict): - if set(value.keys()).intersection(allowed_conditions): - return True - elif key in allowed_conditions: - return True - return False diff --git a/prowler/providers/aws/services/iam/iam_role_cross_service_confused_deputy_prevention/iam_role_cross_service_confused_deputy_prevention.py b/prowler/providers/aws/services/iam/iam_role_cross_service_confused_deputy_prevention/iam_role_cross_service_confused_deputy_prevention.py index 9717101927..11d660a03e 100644 --- a/prowler/providers/aws/services/iam/iam_role_cross_service_confused_deputy_prevention/iam_role_cross_service_confused_deputy_prevention.py +++ b/prowler/providers/aws/services/iam/iam_role_cross_service_confused_deputy_prevention/iam_role_cross_service_confused_deputy_prevention.py @@ -1,8 +1,6 @@ from prowler.lib.check.models import Check, Check_Report_AWS -from prowler.providers.aws.lib.policy_condition_parser.policy_condition_parser import ( - is_condition_block_restrictive, -) from prowler.providers.aws.services.iam.iam_client import iam_client +from prowler.providers.aws.services.iam.lib.policy import is_policy_public class iam_role_cross_service_confused_deputy_prevention(Check): @@ -19,25 +17,12 @@ class iam_role_cross_service_confused_deputy_prevention(Check): report.resource_tags = role.tags report.status = "FAIL" report.status_extended = f"IAM Service Role {role.name} does not prevent against a cross-service confused deputy attack." - for statement in role.assume_role_policy["Statement"]: - if ( - statement["Effect"] == "Allow" - and ( - "sts:AssumeRole" in statement["Action"] - or "sts:*" in statement["Action"] - or "*" in statement["Action"] - ) - # Need to make sure we are checking the part of the assume role policy document that provides a service access - and "Service" in statement["Principal"] - # Check to see if the appropriate condition statements have been implemented - and "Condition" in statement - and is_condition_block_restrictive( - statement["Condition"], iam_client.audited_account - ) - ): - report.status = "PASS" - report.status_extended = f"IAM Service Role {role.name} prevents against a cross-service confused deputy attack." - break + if not is_policy_public( + role.assume_role_policy, + not_allowed_actions=["sts:AssumeRole", "sts:*"], + ): + report.status = "PASS" + report.status_extended = f"IAM Service Role {role.name} prevents against a cross-service confused deputy attack." findings.append(report) diff --git a/prowler/providers/aws/services/iam/lib/policy.py b/prowler/providers/aws/services/iam/lib/policy.py index 27ef05c30f..95af304b3f 100644 --- a/prowler/providers/aws/services/iam/lib/policy.py +++ b/prowler/providers/aws/services/iam/lib/policy.py @@ -43,39 +43,6 @@ def is_policy_cross_account(policy: dict, audited_account: str) -> bool: return False -def is_policy_public(policy: dict) -> bool: - """ - is_policy_public checks if the policy is publicly accessible. - If the "Principal" element value is set to { "AWS": "*" } and the policy statement is not using any Condition clauses to filter the access, the selected policy is publicly accessible. - Args: - policy (dict): The policy to check. - Returns: - bool: True if the policy is publicly accessible, False otherwise. - """ - if policy and "Statement" in policy: - for statement in policy["Statement"]: - if ( - "Principal" in statement - and ( - "*" == statement["Principal"] - or "arn:aws:iam::*:root" in statement["Principal"] - ) - and "Condition" not in statement - ): - return True - elif "Principal" in statement and "AWS" in statement["Principal"]: - if isinstance(statement["Principal"]["AWS"], str): - principals = [statement["Principal"]["AWS"]] - else: - principals = statement["Principal"]["AWS"] - for principal_arn in principals: - if ( - principal_arn == "*" or principal_arn == "arn:aws:iam::*:root" - ) and "Condition" not in statement: - return True - return False - - def check_full_service_access(service: str, policy: dict) -> bool: """ check_full_service_access checks if the policy allows full access to a service. @@ -177,6 +144,259 @@ def is_condition_restricting_from_private_ip(condition_statement: dict) -> bool: return is_from_private_ip +# TODO: Add logic for deny statements +def is_policy_public( + policy: dict, + source_account: str = "", + is_cross_account_allowed=False, + not_allowed_actions: list = [], +) -> bool: + """ + Check if the policy allows public access to the resource. + If the policy gives access to an AWS service principal is considered public if the policy is not pair with conditions since it can be invoked by AWS services in other accounts. + Args: + policy (dict): The AWS policy to check + source_account (str): The account to check if the access is restricted to it, default: "" + is_cross_account_allowed (bool): If the policy can allow cross-account access, default: False + not_allowed_actions (list): List of actions that are not allowed, default: []. If not_allowed_actions is empty, the function will not consider the actions in the policy. + Returns: + bool: True if the policy allows public access, False otherwise + """ + is_public = False + for statement in policy.get("Statement", []): + # Only check allow statements + if statement["Effect"] == "Allow": + principal = statement.get("Principal", "") + if ( + "*" in principal + or "arn:aws:iam::*:root" in principal + or ( + isinstance(principal, dict) + and ( + "*" in principal.get("AWS", "") + or "arn:aws:iam::*:root" in principal.get("AWS", "") + or ( + isinstance(principal.get("AWS"), list) + and ( + "*" in principal["AWS"] + or "arn:aws:iam::*:root" in principal["AWS"] + ) + ) + or "*" in principal.get("CanonicalUser", "") + or "arn:aws:iam::*:root" in principal.get("CanonicalUser", "") + or ( # Check if function can be invoked by other AWS services + ( + ".amazonaws.com" in principal.get("Service", "") + or "*" in principal.get("Service", "") + ) + ) + ) + ) + ) and ( + not not_allowed_actions # If not_allowed_actions is empty, the function will not consider the actions in the policy + or ( + statement.get( + "Action" + ) # If the statement has no action, it is not public + and ( + ( + ( + isinstance(statement.get("Action", ""), list) + and "*" in statement["Action"] + ) + or ( + isinstance(statement.get("Action", ""), str) + and statement.get("Action", "") == "*" + ) + ) + or ( + isinstance(statement.get("Action", ""), list) + and any( + action in not_allowed_actions + for action in statement["Action"] + ) + ) + or (statement.get("Action", "") in not_allowed_actions) + ) + ) + ): + is_public = ( + not is_condition_block_restrictive( + statement.get("Condition", {}), + source_account, + is_cross_account_allowed, + ) + and not is_condition_block_restrictive_organization( + statement.get("Condition", {}) + ) + and not is_condition_restricting_from_private_ip( + statement.get("Condition", {}) + ) + ) + if is_public: + break + return is_public + + +def is_condition_block_restrictive( + condition_statement: dict, + source_account: str = "", + is_cross_account_allowed=False, +): + """ + is_condition_block_restrictive parses the IAM Condition policy block and, by default, returns True if the source_account passed as argument is within, False if not. + + If argument is_cross_account_allowed is True it tests if the Condition block includes any of the operators allowlisted returning True if does, False if not. + + Args: + condition_statement: dict with an IAM Condition block, e.g.: + { + "StringLike": { + "AWS:SourceAccount": 111122223333 + } + } + + source_account: str with a 12-digit AWS Account number, e.g.: 111122223333, default: "" + + is_cross_account_allowed: bool to allow cross-account access, e.g.: True, default: False + + """ + is_condition_valid = False + + # The conditions must be defined in lowercase since the context key names are not case-sensitive. + # For example, including the aws:SourceAccount context key is equivalent to testing for AWS:SourceAccount + # https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html + valid_condition_options = { + "StringEquals": [ + "aws:sourceaccount", + "aws:sourceowner", + "s3:resourceaccount", + "aws:principalaccount", + "aws:resourceaccount", + "aws:sourcearn", + "aws:sourcevpc", + "aws:sourcevpce", + ], + "StringLike": [ + "aws:sourceaccount", + "aws:sourceowner", + "aws:sourcearn", + "aws:principalarn", + "aws:resourceaccount", + "aws:principalaccount", + "aws:sourcevpc", + "aws:sourcevpce", + ], + "ArnLike": ["aws:sourcearn", "aws:principalarn"], + "ArnEquals": ["aws:sourcearn", "aws:principalarn"], + } + + for condition_operator, condition_operator_key in valid_condition_options.items(): + if condition_operator in condition_statement: + for value in condition_operator_key: + # We need to transform the condition_statement into lowercase + condition_statement[condition_operator] = { + k.lower(): v + for k, v in condition_statement[condition_operator].items() + } + + if value in condition_statement[condition_operator]: + # values are a list + if isinstance( + condition_statement[condition_operator][value], + list, + ): + is_condition_key_restrictive = True + # if cross account is not allowed check for each condition block looking for accounts + # different than default + if not is_cross_account_allowed: + # if there is an arn/account without the source account -> we do not consider it safe + # here by default we assume is true and look for false entries + for item in condition_statement[condition_operator][value]: + if source_account not in item: + is_condition_key_restrictive = False + break + + if is_condition_key_restrictive: + is_condition_valid = True + + # value is a string + elif isinstance( + condition_statement[condition_operator][value], + str, + ): + if is_cross_account_allowed: + is_condition_valid = True + else: + if ( + source_account + in condition_statement[condition_operator][value] + ): + is_condition_valid = True + + return is_condition_valid + + +def is_condition_block_restrictive_organization( + condition_statement: dict, +): + """ + is_condition_block_restrictive_organization parses the IAM Condition policy block and returns True if the condition_statement is restrictive for the organization, False if not. + + @param condition_statement: dict with an IAM Condition block, e.g.: + { + "StringLike": { + "AWS:PrincipalOrgID": "o-111122223333" + } + } + + """ + is_condition_valid = False + + # The conditions must be defined in lowercase since the context key names are not case-sensitive. + # For example, including the aws:PrincipalOrgID context key is equivalent to testing for AWS:PrincipalOrgID + # https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html + valid_condition_options = { + "StringEquals": [ + "aws:principalorgid", + ], + "StringLike": [ + "aws:principalorgid", + ], + } + + for condition_operator, condition_operator_key in valid_condition_options.items(): + if condition_operator in condition_statement: + for value in condition_operator_key: + # We need to transform the condition_statement into lowercase + condition_statement[condition_operator] = { + k.lower(): v + for k, v in condition_statement[condition_operator].items() + } + + if value in condition_statement[condition_operator]: + # values are a list + if isinstance( + condition_statement[condition_operator][value], + list, + ): + is_condition_valid = True + for item in condition_statement[condition_operator][value]: + if item == "*": + is_condition_valid = False + break + + # value is a string + elif isinstance( + condition_statement[condition_operator][value], + str, + ): + if "*" not in condition_statement[condition_operator][value]: + is_condition_valid = True + + return is_condition_valid + + def process_actions(effect, actions, target_set): """ process_actions processes the actions in the policy. diff --git a/prowler/providers/aws/services/kms/kms_key_not_publicly_accessible/kms_key_not_publicly_accessible.py b/prowler/providers/aws/services/kms/kms_key_not_publicly_accessible/kms_key_not_publicly_accessible.py index 62ed3fac24..e821c6bc13 100644 --- a/prowler/providers/aws/services/kms/kms_key_not_publicly_accessible/kms_key_not_publicly_accessible.py +++ b/prowler/providers/aws/services/kms/kms_key_not_publicly_accessible/kms_key_not_publicly_accessible.py @@ -1,4 +1,5 @@ from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.iam.lib.policy import is_policy_public from prowler.providers.aws.services.kms.kms_client import kms_client @@ -17,32 +18,10 @@ class kms_key_not_publicly_accessible(Check): report.resource_tags = key.tags report.region = key.region # If the "Principal" element value is set to { "AWS": "*" } and the policy statement is not using any Condition clauses to filter the access, the selected AWS KMS master key is publicly accessible. - if key.policy and "Statement" in key.policy: - for statement in key.policy["Statement"]: - if ( - "Principal" in statement - and "*" == statement["Principal"] - and "Condition" not in statement - ): - report.status = "FAIL" - report.status_extended = ( - f"KMS key {key.id} may be publicly accessible." - ) - elif ( - "Principal" in statement and "AWS" in statement["Principal"] - ): - if isinstance(statement["Principal"]["AWS"], str): - principals = [statement["Principal"]["AWS"]] - else: - principals = statement["Principal"]["AWS"] - for principal_arn in principals: - if ( - principal_arn == "*" - and "Condition" not in statement - ): - report.status = "FAIL" - report.status_extended = ( - f"KMS key {key.id} may be publicly accessible." - ) + if is_policy_public(key.policy, not_allowed_actions=["kms:*"]): + report.status = "FAIL" + report.status_extended = ( + f"KMS key {key.id} may be publicly accessible." + ) findings.append(report) return findings diff --git a/prowler/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access.py b/prowler/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access.py index 33353d243b..8ad4011ebb 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access.py +++ b/prowler/providers/aws/services/s3/s3_bucket_policy_public_write_access/s3_bucket_policy_public_write_access.py @@ -1,4 +1,5 @@ from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.iam.lib.policy import is_policy_public from prowler.providers.aws.services.s3.s3_client import s3_client from prowler.providers.aws.services.s3.s3control_client import s3control_client @@ -37,37 +38,18 @@ class s3_bucket_policy_public_write_access(Check): else: report.status = "PASS" report.status_extended = f"S3 Bucket {bucket.name} does not allow public write access in the bucket policy." - for statement in bucket.policy["Statement"]: - if ( - statement["Effect"] == "Allow" - and "Condition" not in statement - and ( - "Principal" in statement - and "*" in str(statement["Principal"]) - ) - and ( - ( - isinstance(statement["Action"], list) - and ( - "s3:PutObject" in statement["Action"] - or "*" in statement["Action"] - or "s3:*" in statement["Action"] - or "s3:Put*" in statement["Action"] - ) - ) - or ( - isinstance(statement["Action"], str) - and ( - "s3:PutObject" == statement["Action"] - or "*" == statement["Action"] - or "s3:*" == statement["Action"] - or "s3:Put*" == statement["Action"] - ) - ) - ) - ): - report.status = "FAIL" - report.status_extended = f"S3 Bucket {bucket.name} allows public write access in the bucket policy." + if is_policy_public( + bucket.policy, + not_allowed_actions=[ + "s3:PutObject", + "s3:DeleteObject", + "s3:*", + "s3:Put*", + "s3:Delete*", + ], + ): + report.status = "FAIL" + report.status_extended = f"S3 Bucket {bucket.name} allows public write access in the bucket policy." findings.append(report) return findings diff --git a/prowler/providers/aws/services/s3/s3_bucket_public_access/s3_bucket_public_access.py b/prowler/providers/aws/services/s3/s3_bucket_public_access/s3_bucket_public_access.py index a8658c094d..4278688724 100644 --- a/prowler/providers/aws/services/s3/s3_bucket_public_access/s3_bucket_public_access.py +++ b/prowler/providers/aws/services/s3/s3_bucket_public_access/s3_bucket_public_access.py @@ -1,10 +1,5 @@ from prowler.lib.check.models import Check, Check_Report_AWS -from prowler.providers.aws.lib.policy_condition_parser.policy_condition_parser import ( - is_condition_block_restrictive, -) -from prowler.providers.aws.services.iam.lib.policy import ( - is_condition_restricting_from_private_ip, -) +from prowler.providers.aws.services.iam.lib.policy import is_policy_public from prowler.providers.aws.services.s3.s3_client import s3_client from prowler.providers.aws.services.s3.s3control_client import s3control_client @@ -51,39 +46,8 @@ class s3_bucket_public_access(Check): report.status_extended = f"S3 Bucket {bucket.name} has public access due to bucket ACL." # 4. Check bucket policy - if bucket.policy: - for statement in bucket.policy.get("Statement", []): - if ( - "Principal" in statement - and statement["Effect"] == "Allow" - and not is_condition_block_restrictive( - statement.get("Condition", {}), "", True - ) - and ( - not is_condition_restricting_from_private_ip( - statement.get("Condition", {}) - ) - if statement.get("Condition", {}).get( - "IpAddress", {} - ) - else True - ) - ): - if "*" == statement["Principal"]: - report.status = "FAIL" - report.status_extended = f"S3 Bucket {bucket.name} has public access due to bucket policy." - elif "AWS" in statement["Principal"]: - principals = ( - statement["Principal"]["AWS"] - if isinstance( - statement["Principal"]["AWS"], list - ) - else [statement["Principal"]["AWS"]] - ) - - for principal_arn in principals: - if principal_arn == "*": - report.status = "FAIL" - report.status_extended = f"S3 Bucket {bucket.name} has public access due to bucket policy." + if is_policy_public(bucket.policy): + report.status = "FAIL" + report.status_extended = f"S3 Bucket {bucket.name} has public access due to bucket policy." findings.append(report) return findings diff --git a/prowler/providers/aws/services/sns/sns_topics_not_publicly_accessible/sns_topics_not_publicly_accessible.py b/prowler/providers/aws/services/sns/sns_topics_not_publicly_accessible/sns_topics_not_publicly_accessible.py index fc93cbbcc4..091e5729e7 100644 --- a/prowler/providers/aws/services/sns/sns_topics_not_publicly_accessible/sns_topics_not_publicly_accessible.py +++ b/prowler/providers/aws/services/sns/sns_topics_not_publicly_accessible/sns_topics_not_publicly_accessible.py @@ -1,5 +1,5 @@ from prowler.lib.check.models import Check, Check_Report_AWS -from prowler.providers.aws.lib.policy_condition_parser.policy_condition_parser import ( +from prowler.providers.aws.services.iam.lib.policy import ( is_condition_block_restrictive, is_condition_block_restrictive_organization, ) diff --git a/prowler/providers/aws/services/sqs/sqs_queues_not_publicly_accessible/sqs_queues_not_publicly_accessible.py b/prowler/providers/aws/services/sqs/sqs_queues_not_publicly_accessible/sqs_queues_not_publicly_accessible.py index a21e5a8c00..e649498b77 100644 --- a/prowler/providers/aws/services/sqs/sqs_queues_not_publicly_accessible/sqs_queues_not_publicly_accessible.py +++ b/prowler/providers/aws/services/sqs/sqs_queues_not_publicly_accessible/sqs_queues_not_publicly_accessible.py @@ -1,7 +1,5 @@ from prowler.lib.check.models import Check, Check_Report_AWS -from prowler.providers.aws.lib.policy_condition_parser.policy_condition_parser import ( - is_condition_block_restrictive, -) +from prowler.providers.aws.services.iam.lib.policy import is_condition_block_restrictive from prowler.providers.aws.services.sqs.sqs_client import sqs_client diff --git a/prowler/providers/aws/services/vpc/vpc_endpoint_connections_trust_boundaries/vpc_endpoint_connections_trust_boundaries.py b/prowler/providers/aws/services/vpc/vpc_endpoint_connections_trust_boundaries/vpc_endpoint_connections_trust_boundaries.py index 936057e657..4cac25481b 100644 --- a/prowler/providers/aws/services/vpc/vpc_endpoint_connections_trust_boundaries/vpc_endpoint_connections_trust_boundaries.py +++ b/prowler/providers/aws/services/vpc/vpc_endpoint_connections_trust_boundaries/vpc_endpoint_connections_trust_boundaries.py @@ -1,9 +1,7 @@ from re import compile from prowler.lib.check.models import Check, Check_Report_AWS -from prowler.providers.aws.lib.policy_condition_parser.policy_condition_parser import ( - is_condition_block_restrictive, -) +from prowler.providers.aws.services.iam.lib.policy import is_condition_block_restrictive from prowler.providers.aws.services.vpc.vpc_client import vpc_client diff --git a/tests/providers/aws/lib/policy_condition_parser/policy_condition_parser_test.py b/tests/providers/aws/lib/policy_condition_parser/policy_condition_parser_test.py deleted file mode 100644 index 0162064bd2..0000000000 --- a/tests/providers/aws/lib/policy_condition_parser/policy_condition_parser_test.py +++ /dev/null @@ -1,1439 +0,0 @@ -from prowler.providers.aws.lib.policy_condition_parser.policy_condition_parser import ( - is_condition_block_restrictive, - is_condition_block_restrictive_organization, -) - -TRUSTED_AWS_ACCOUNT_NUMBER = "123456789012" -NON_TRUSTED_AWS_ACCOUNT_NUMBER = "111222333444" - -TRUSTED_ORGANIZATION_ID = "o-123456789012" -NON_TRUSTED_ORGANIZATION_ID = "o-111222333444" - -ALL_ORGS = "*" - - -class Test_policy_condition_parser: - # Test lowercase context key name --> aws - def test_condition_parser_string_equals_aws_SourceAccount_list(self): - condition_statement = { - "StringEquals": {"aws:SourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_SourceAccount_list_not_valid(self): - condition_statement = { - "StringEquals": { - "aws:SourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_SourceAccount_str(self): - condition_statement = { - "StringEquals": {"aws:SourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_SourceAccount_str_not_valid(self): - condition_statement = { - "StringEquals": {"aws:SourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_SourceAccount_list(self): - condition_statement = { - "StringLike": {"aws:SourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_SourceAccount_list_not_valid(self): - condition_statement = { - "StringLike": { - "aws:SourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_SourceAccount_str(self): - condition_statement = { - "StringLike": {"aws:SourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_SourceAccount_str_not_valid(self): - condition_statement = { - "StringLike": {"aws:SourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_SourceOwner_str(self): - condition_statement = { - "StringEquals": {"aws:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_SourceOwner_str_not_valid(self): - condition_statement = { - "StringEquals": {"aws:SourceOwner": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_SourceOwner_list(self): - condition_statement = { - "StringEquals": {"aws:SourceOwner": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_SourceOwner_list_not_valid(self): - condition_statement = { - "StringEquals": { - "aws:SourceOwner": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_SourceOwner_list(self): - condition_statement = { - "StringLike": {"aws:SourceOwner": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_SourceOwner_list_not_valid(self): - condition_statement = { - "StringLike": { - "aws:SourceOwner": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_SourceOwner_str(self): - condition_statement = { - "StringLike": {"aws:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_SourceOwner_str_not_valid(self): - condition_statement = { - "StringLike": {"aws:SourceOwner": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_s3_ResourceAccount_list(self): - condition_statement = { - "StringEquals": {"s3:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_s3_ResourceAccount_list_not_valid(self): - condition_statement = { - "StringEquals": { - "s3:ResourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_s3_ResourceAccount_str(self): - condition_statement = { - "StringEquals": {"s3:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_s3_ResourceAccount_str_not_valid(self): - condition_statement = { - "StringEquals": {"s3:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_PrincipalAccount_list(self): - condition_statement = { - "StringEquals": {"aws:PrincipalAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_PrincipalAccount_list_not_valid(self): - condition_statement = { - "StringEquals": { - "aws:PrincipalAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_PrincipalAccount_str(self): - condition_statement = { - "StringEquals": {"aws:PrincipalAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_PrincipalAccount_str_not_valid(self): - condition_statement = { - "StringEquals": {"aws:PrincipalAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_SourceArn_str(self): - condition_statement = { - "StringEquals": { - "aws:SourceArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - } - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_SourceArn_str_not_valid(self): - condition_statement = { - "StringEquals": { - "aws:SourceArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_PrincipalAccount_list(self): - condition_statement = { - "StringLike": {"aws:PrincipalAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_PrincipalAccount_list_not_valid(self): - condition_statement = { - "StringLike": { - "aws:PrincipalAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_PrincipalAccount_str(self): - condition_statement = { - "StringLike": {"aws:PrincipalAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_PrincipalAccount_str_not_valid(self): - condition_statement = { - "StringLike": {"aws:PrincipalAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_aws_SourceArn_list(self): - condition_statement = { - "ArnLike": { - "aws:SourceArn": [ - f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - ] - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_aws_SourceArn_list_not_valid(self): - condition_statement = { - "ArnLike": { - "aws:SourceArn": [ - f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - ] - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_aws_SourceArn_str(self): - condition_statement = { - "ArnLike": { - "aws:SourceArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_aws_SourceArn_str_not_valid(self): - condition_statement = { - "ArnLike": { - "aws:SourceArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_aws_PrincipalArn_list(self): - condition_statement = { - "ArnLike": { - "aws:PrincipalArn": [ - f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - ] - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_aws_PrincipalArn_list_not_valid(self): - condition_statement = { - "ArnLike": { - "aws:PrincipalArn": [ - f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - ] - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_aws_PrincipalArn_str(self): - condition_statement = { - "ArnLike": { - "aws:PrincipalArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_aws_PrincipalArn_str_not_valid(self): - condition_statement = { - "ArnLike": { - "aws:PrincipalArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_aws_SourceArn_list(self): - condition_statement = { - "ArnEquals": { - "aws:SourceArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - ] - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_aws_SourceArn_list_not_valid(self): - condition_statement = { - "ArnEquals": { - "aws:SourceArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - ] - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_aws_SourceArn_str(self): - condition_statement = { - "ArnEquals": { - "aws:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_aws_SourceArn_str_not_valid(self): - condition_statement = { - "ArnEquals": { - "aws:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_aws_PrincipalArn_list(self): - condition_statement = { - "ArnEquals": { - "aws:PrincipalArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - ] - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_aws_PrincipalArn_list_not_valid(self): - condition_statement = { - "ArnEquals": { - "aws:PrincipalArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - ] - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_aws_PrincipalArn_str(self): - condition_statement = { - "ArnEquals": { - "aws:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_aws_PrincipalArn_str_not_valid(self): - condition_statement = { - "ArnEquals": { - "aws:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_SourceArn_list(self): - condition_statement = { - "StringLike": { - "aws:SourceArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - ] - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_SourceArn_list_not_valid(self): - condition_statement = { - "StringLike": { - "aws:SourceArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - ] - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_SourceArn_str(self): - condition_statement = { - "StringLike": { - "aws:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_SourceArn_str_not_valid(self): - condition_statement = { - "StringLike": { - "aws:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_PrincipalArn_list(self): - condition_statement = { - "StringLike": { - "aws:PrincipalArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - ] - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_PrincipalArn_list_not_valid(self): - condition_statement = { - "StringLike": { - "aws:PrincipalArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - ] - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_PrincipalArn_str(self): - condition_statement = { - "StringLike": { - "aws:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_PrincipalArn_str_not_valid(self): - condition_statement = { - "StringLike": { - "aws:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_ResourceAccount_list(self): - condition_statement = { - "StringEquals": {"aws:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_ResourceAccount_list_not_valid(self): - condition_statement = { - "StringEquals": { - "aws:ResourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_ResourceAccount_str(self): - condition_statement = { - "StringEquals": {"aws:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_aws_ResourceAccount_str_not_valid(self): - condition_statement = { - "StringEquals": {"aws:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_ResourceAccount_list(self): - condition_statement = { - "StringLike": {"aws:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_ResourceAccount_list_not_valid(self): - condition_statement = { - "StringLike": { - "aws:ResourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_ResourceAccount_str(self): - condition_statement = { - "StringLike": {"aws:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_aws_ResourceAccount_str_not_valid(self): - condition_statement = { - "StringLike": {"aws:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - # Test uppercase context key name --> AWS - def test_condition_parser_string_equals_AWS_SourceAccount_list(self): - condition_statement = { - "StringEquals": {"AWS:SourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_SourceAccount_list_not_valid(self): - condition_statement = { - "StringEquals": { - "AWS:SourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_SourceAccount_str(self): - condition_statement = { - "StringEquals": {"AWS:SourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_SourceAccount_str_not_valid(self): - condition_statement = { - "StringEquals": {"AWS:SourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_SourceAccount_list(self): - condition_statement = { - "StringLike": {"AWS:SourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_SourceAccount_list_not_valid(self): - condition_statement = { - "StringLike": { - "AWS:SourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_SourceAccount_str(self): - condition_statement = { - "StringLike": {"AWS:SourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_SourceAccount_str_not_valid(self): - condition_statement = { - "StringLike": {"AWS:SourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_SourceOwner_str(self): - condition_statement = { - "StringEquals": {"AWS:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_SourceOwner_str_not_valid(self): - condition_statement = { - "StringEquals": {"AWS:SourceOwner": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_SourceOwner_list(self): - condition_statement = { - "StringEquals": {"AWS:SourceOwner": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_SourceOwner_list_not_valid(self): - condition_statement = { - "StringEquals": { - "AWS:SourceOwner": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_SourceOwner_list(self): - condition_statement = { - "StringLike": {"AWS:SourceOwner": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_SourceOwner_list_not_valid(self): - condition_statement = { - "StringLike": { - "AWS:SourceOwner": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_SourceOwner_str(self): - condition_statement = { - "StringLike": {"AWS:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_SourceOwner_str_not_valid(self): - condition_statement = { - "StringLike": {"AWS:SourceOwner": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_S3_ResourceAccount_list(self): - condition_statement = { - "StringEquals": {"S3:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_S3_ResourceAccount_list_not_valid(self): - condition_statement = { - "StringEquals": { - "S3:ResourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_S3_ResourceAccount_str(self): - condition_statement = { - "StringEquals": {"S3:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_S3_ResourceAccount_str_not_valid(self): - condition_statement = { - "StringEquals": {"S3:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_PrincipalAccount_list(self): - condition_statement = { - "StringEquals": {"AWS:PrincipalAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_PrincipalAccount_list_not_valid(self): - condition_statement = { - "StringEquals": { - "AWS:PrincipalAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_PrincipalAccount_str(self): - condition_statement = { - "StringEquals": {"AWS:PrincipalAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_PrincipalAccount_str_not_valid(self): - condition_statement = { - "StringEquals": {"AWS:PrincipalAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_PrincipalAccount_list(self): - condition_statement = { - "StringLike": {"AWS:PrincipalAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_PrincipalAccount_list_not_valid(self): - condition_statement = { - "StringLike": { - "AWS:PrincipalAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_PrincipalAccount_str(self): - condition_statement = { - "StringLike": {"AWS:PrincipalAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_PrincipalAccount_str_not_valid(self): - condition_statement = { - "StringLike": {"AWS:PrincipalAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_AWS_SourceArn_list(self): - condition_statement = { - "ArnLike": { - "AWS:SourceArn": [ - f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - ] - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_AWS_SourceArn_list_not_valid(self): - condition_statement = { - "ArnLike": { - "AWS:SourceArn": [ - f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - ] - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_AWS_SourceArn_str(self): - condition_statement = { - "ArnLike": { - "AWS:SourceArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_AWS_SourceArn_str_not_valid(self): - condition_statement = { - "ArnLike": { - "AWS:SourceArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_AWS_PrincipalArn_list(self): - condition_statement = { - "ArnLike": { - "AWS:PrincipalArn": [ - f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - ] - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_AWS_PrincipalArn_list_not_valid(self): - condition_statement = { - "ArnLike": { - "AWS:PrincipalArn": [ - f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - ] - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_AWS_PrincipalArn_str(self): - condition_statement = { - "ArnLike": { - "AWS:PrincipalArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_like_AWS_PrincipalArn_str_not_valid(self): - condition_statement = { - "ArnLike": { - "AWS:PrincipalArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_AWS_SourceArn_list(self): - condition_statement = { - "ArnEquals": { - "AWS:SourceArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - ] - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_AWS_SourceArn_list_not_valid(self): - condition_statement = { - "ArnEquals": { - "AWS:SourceArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - ] - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_AWS_SourceArn_str(self): - condition_statement = { - "ArnEquals": { - "AWS:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_AWS_SourceArn_str_not_valid(self): - condition_statement = { - "ArnEquals": { - "AWS:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_AWS_PrincipalArn_list(self): - condition_statement = { - "ArnEquals": { - "AWS:PrincipalArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - ] - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_AWS_PrincipalArn_list_not_valid(self): - condition_statement = { - "ArnEquals": { - "AWS:PrincipalArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - ] - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_AWS_PrincipalArn_str(self): - condition_statement = { - "ArnEquals": { - "AWS:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_arn_equals_AWS_PrincipalArn_str_not_valid(self): - condition_statement = { - "ArnEquals": { - "AWS:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_SourceArn_list(self): - condition_statement = { - "StringLike": { - "AWS:SourceArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - ] - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_SourceArn_list_not_valid(self): - condition_statement = { - "StringLike": { - "AWS:SourceArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - ] - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_SourceArn_str(self): - condition_statement = { - "StringLike": { - "AWS:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_SourceArn_str_not_valid(self): - condition_statement = { - "StringLike": { - "AWS:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_PrincipalArn_list(self): - condition_statement = { - "StringLike": { - "AWS:PrincipalArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - ] - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_PrincipalArn_list_not_valid(self): - condition_statement = { - "StringLike": { - "AWS:PrincipalArn": [ - f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", - ] - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_PrincipalArn_str(self): - condition_statement = { - "StringLike": { - "AWS:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_PrincipalArn_str_not_valid(self): - condition_statement = { - "StringLike": { - "AWS:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" - } - } - - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_ResourceAccount_list(self): - condition_statement = { - "StringEquals": {"AWS:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_ResourceAccount_list_not_valid(self): - condition_statement = { - "StringEquals": { - "AWS:ResourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_ResourceAccount_str(self): - condition_statement = { - "StringEquals": {"AWS:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_equals_AWS_ResourceAccount_str_not_valid(self): - condition_statement = { - "StringEquals": {"AWS:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_ResourceAccount_list(self): - condition_statement = { - "StringLike": {"AWS:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_ResourceAccount_list_not_valid(self): - condition_statement = { - "StringLike": { - "AWS:ResourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - } - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_ResourceAccount_str(self): - condition_statement = { - "StringLike": {"AWS:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_string_like_AWS_ResourceAccount_str_not_valid(self): - condition_statement = { - "StringLike": {"AWS:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_two_lists_unrestrictive(self): - condition_statement = { - "StringLike": { - "AWS:ResourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - }, - "ArnLike": { - "AWS:SourceArn": [ - f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - ] - }, - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_two_lists_both_restrictive(self): - condition_statement = { - "StringLike": { - "AWS:ResourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - ] - }, - "ArnLike": { - "AWS:SourceArn": [ - f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - ] - }, - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_two_lists_first_restrictive(self): - condition_statement = { - "StringLike": { - "AWS:ResourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - ] - }, - "ArnLike": { - "AWS:SourceArn": [ - f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - ] - }, - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_two_lists_second_restrictive(self): - condition_statement = { - "StringLike": { - "AWS:ResourceAccount": [ - TRUSTED_AWS_ACCOUNT_NUMBER, - NON_TRUSTED_AWS_ACCOUNT_NUMBER, - ] - }, - "ArnLike": { - "AWS:SourceArn": [ - f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", - ] - }, - } - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER - ) - - def test_condition_parser_allowing_cross_account_with_invalid_block(self): - condition_statement = { - "StringLike": { - "s3:prefix": [ - "home/", - ] - }, - } - assert not is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER, True - ) - - def test_condition_parser_string_equals_vpc(self): - condition_statement = {"StringEquals": {"aws:SourceVpc": "vpc-123456"}} - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER, True - ) - - def test_condition_parser_string_equals_vpc_list(self): - condition_statement = {"StringEquals": {"aws:sourcevpc": ["vpc-123456"]}} - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER, True - ) - - def test_condition_parser_string_equals_vpc_list_not_valid(self): - condition_statement = { - "StringEquals": {"aws:SourceVpc": ["vpc-123456", "vpc-654321"]} - } - - assert is_condition_block_restrictive( - condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER, True - ) - - def test_condition_parser_string_equals_aws_PrincipalOrgID_list(self): - condition_statement = { - "StringEquals": {"aws:PrincipalOrgID": [TRUSTED_ORGANIZATION_ID]} - } - assert is_condition_block_restrictive_organization(condition_statement) - - def test_condition_parser_string_equals_aws_PrincipalOrgID_list_multiple_items( - self, - ): - condition_statement = { - "StringEquals": { - "aws:PrincipalOrgID": [ - TRUSTED_ORGANIZATION_ID, - NON_TRUSTED_ORGANIZATION_ID, - ] - } - } - assert is_condition_block_restrictive_organization(condition_statement) - - def test_condition_parser_string_equals_aws_PrincipalOrgID_str(self): - condition_statement = { - "StringEquals": {"aws:PrincipalOrgID": TRUSTED_ORGANIZATION_ID} - } - assert is_condition_block_restrictive_organization(condition_statement) - - def test_condition_parser_string_equals_aws_All_Orgs_list_multiple_items( - self, - ): - condition_statement = { - "StringEquals": { - "aws:PrincipalOrgID": [ - TRUSTED_ORGANIZATION_ID, - ALL_ORGS, - ] - } - } - assert not is_condition_block_restrictive_organization(condition_statement) - - def test_condition_parser_string_equals_aws_All_Orgs_str(self): - condition_statement = {"StringEquals": {"aws:PrincipalOrgID": ALL_ORGS}} - assert not is_condition_block_restrictive_organization(condition_statement) diff --git a/tests/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible_test.py b/tests/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible_test.py index 86c240c8c9..4278b991d8 100644 --- a/tests/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible_test.py +++ b/tests/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible_test.py @@ -79,7 +79,6 @@ class Test_awslambda_function_not_publicly_accessible: StatementId="public-access", Action="lambda:InvokeFunction", Principal="*", - SourceArn=function_arn, ) aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) @@ -112,6 +111,83 @@ class Test_awslambda_function_not_publicly_accessible: ) assert result[0].resource_tags == [{"tag1": "value1", "tag2": "value2"}] + @mock_aws + def test_function_public_with_source_account(self): + # Create the mock IAM role + iam_client = client("iam", region_name=AWS_REGION_EU_WEST_1) + role_name = "test-role" + assume_role_policy_document = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"Service": "lambda.amazonaws.com"}, + "Action": "sts:AssumeRole", + } + ], + } + role_arn = iam_client.create_role( + RoleName=role_name, + AssumeRolePolicyDocument=dumps(assume_role_policy_document), + )["Role"]["Arn"] + + function_name = "test-lambda" + + # Create the lambda function using boto3 client + lambda_client = client("lambda", region_name=AWS_REGION_EU_WEST_1) + function_arn = lambda_client.create_function( + FunctionName=function_name, + Runtime="nodejs4.3", + Role=role_arn, + Handler="index.handler", + Code={"ZipFile": b"fileb://file-path/to/your-deployment-package.zip"}, + Description="Test Lambda function", + Timeout=3, + MemorySize=128, + Publish=True, + Tags={"tag1": "value1", "tag2": "value2"}, + )["FunctionArn"] + + # Attach the policy to the lambda function with a wildcard principal + lambda_client.add_permission( + FunctionName=function_name, + StatementId="non-public-access", + Action="lambda:InvokeFunction", + Principal="*", + SourceArn=function_arn, + SourceAccount=AWS_ACCOUNT_NUMBER, + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + from prowler.providers.aws.services.awslambda.awslambda_service import Lambda + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible.awslambda_client", + new=Lambda(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible import ( + awslambda_function_not_publicly_accessible, + ) + + check = awslambda_function_not_publicly_accessible() + result = check.execute() + + assert len(result) == 1 + assert result[0].region == AWS_REGION_EU_WEST_1 + assert result[0].resource_id == function_name + assert result[0].resource_arn == function_arn + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Lambda function {function_name} has a policy resource-based policy not public." + ) + assert result[0].resource_tags == [{"tag1": "value1", "tag2": "value2"}] + @mock_aws def test_function_not_public(self): # Create the mock IAM role @@ -190,6 +266,7 @@ class Test_awslambda_function_not_publicly_accessible: def test_function_public_with_canonical(self): lambda_client = mock.MagicMock + lambda_client.audited_account = AWS_ACCOUNT_NUMBER function_name = "test-lambda" function_runtime = "nodejs4.3" function_arn = f"arn:aws:lambda:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:function/{function_name}" @@ -418,59 +495,190 @@ class Test_awslambda_function_not_publicly_accessible: ) assert result[0].resource_tags == [{"tag1": "value1", "tag2": "value2"}] - # def test_function_could_be_invoked_by_specific_aws_account(self): - # lambda_client = mock.MagicMock - # function_name = "test-lambda" - # function_runtime = "nodejs4.3" - # function_arn = f"arn:aws:lambda:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:function/{function_name}" - # lambda_policy = { # If there is an ALB or API Gateway in specified AWS Account, the lambda function could be invoked and exposed by them - # "Version": "2012-10-17", - # "Statement": [ - # { - # "Sid": "public-access", - # "Principal": {"AWS": AWS_ACCOUNT_NUMBER}, - # "Effect": "Allow", - # "Action": [ - # "lambda:InvokeFunction", - # ], - # "Resource": [function_arn], - # } - # ], - # } + def test_function_could_be_invoked_by_specific_aws_account(self): + lambda_client = mock.MagicMock + lambda_client.audited_account = AWS_ACCOUNT_NUMBER + function_name = "test-lambda" + function_runtime = "nodejs4.3" + function_arn = f"arn:aws:lambda:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:function/{function_name}" + lambda_policy = { + "Version": "2012-10-17", + "Id": "default", + "Statement": [ + { + "Sid": "awslambda-myLambdaScript-LambdaInvokePermission", + "Effect": "Allow", + "Principal": {"Service": "ses.amazonaws.com"}, + "Action": "lambda:InvokeFunction", + "Resource": f"arn:aws:lambda:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:function:{function_name}", + "Condition": { + "StringEquals": {"AWS:SourceAccount": AWS_ACCOUNT_NUMBER} + }, + } + ], + } - # lambda_client.functions = { - # "function_name": Function( - # name=function_name, - # security_groups=[], - # arn=function_arn, - # region=AWS_REGION_EU_WEST_1, - # runtime=function_runtime, - # policy=lambda_policy, - # ) - # } + lambda_client.functions = { + "function_name": Function( + name=function_name, + security_groups=[], + arn=function_arn, + region=AWS_REGION_EU_WEST_1, + runtime=function_runtime, + policy=lambda_policy, + ) + } - # with mock.patch( - # "prowler.providers.common.provider.Provider.get_global_provider", - # return_value=set_mocked_aws_provider(), - # ), mock.patch( - # "prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible.awslambda_client", - # new=lambda_client, - # ): - # # Test Check - # from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible import ( - # awslambda_function_not_publicly_accessible, - # ) + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_aws_provider(), + ), mock.patch( + "prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible.awslambda_client", + new=lambda_client, + ): + from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible import ( + awslambda_function_not_publicly_accessible, + ) - # check = awslambda_function_not_publicly_accessible() - # result = check.execute() + check = awslambda_function_not_publicly_accessible() + result = check.execute() - # assert len(result) == 1 - # assert result[0].region == AWS_REGION_EU_WEST_1 - # assert result[0].resource_id == function_name - # assert result[0].resource_arn == function_arn - # assert result[0].status == "FAIL" - # assert ( - # result[0].status_extended - # == f"Lambda function {function_name} has a policy resource-based policy with public access." - # ) - # assert result[0].resource_tags == [] + assert len(result) == 1 + assert result[0].region == AWS_REGION_EU_WEST_1 + assert result[0].resource_id == function_name + assert result[0].resource_arn == function_arn + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Lambda function {function_name} has a policy resource-based policy not public." + ) + assert result[0].resource_tags == [] + + def test_function_could_be_invoked_by_specific_other_aws_account(self): + lambda_client = mock.MagicMock + lambda_client.audited_account = AWS_ACCOUNT_NUMBER + function_name = "test-lambda" + function_runtime = "nodejs4.3" + function_arn = f"arn:aws:lambda:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:function/{function_name}" + lambda_policy = { + "Version": "2012-10-17", + "Id": "default", + "Statement": [ + { + "Sid": "awslambda-myLambdaScript-LambdaInvokePermission", + "Effect": "Allow", + "Principal": {"Service": "ses.amazonaws.com"}, + "Action": "lambda:InvokeFunction", + "Resource": f"arn:aws:lambda:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:function:{function_name}", + "Condition": { + "StringEquals": {"AWS:SourceAccount": "000000000000"} + }, + } + ], + } + + lambda_client.functions = { + "function_name": Function( + name=function_name, + security_groups=[], + arn=function_arn, + region=AWS_REGION_EU_WEST_1, + runtime=function_runtime, + policy=lambda_policy, + ) + } + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_aws_provider(), + ), mock.patch( + "prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible.awslambda_client", + new=lambda_client, + ): + from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible import ( + awslambda_function_not_publicly_accessible, + ) + + check = awslambda_function_not_publicly_accessible() + result = check.execute() + + assert len(result) == 1 + assert result[0].region == AWS_REGION_EU_WEST_1 + assert result[0].resource_id == function_name + assert result[0].resource_arn == function_arn + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Lambda function {function_name} has a policy resource-based policy not public." + ) + assert result[0].resource_tags == [] + + def test_function_public_policy_with_several_statements(self): + lambda_client = mock.MagicMock + lambda_client.audited_account = AWS_ACCOUNT_NUMBER + function_name = "test-lambda" + function_runtime = "nodejs4.3" + function_arn = f"arn:aws:lambda:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:function/{function_name}" + lambda_policy = { + "Version": "2012-10-17", + "Id": "default", + "Statement": [ + { + "Sid": "AllowExecutionFromAPIGateway", + "Effect": "Allow", + "Principal": {"Service": "apigateway.amazonaws.com"}, + "Action": "lambda:InvokeFunction", + "Resource": f"arn:aws:lambda:eu-central-1:{AWS_ACCOUNT_NUMBER}:function:foo", + "Condition": { + "ArnLike": { + "AWS:SourceArn": f"arn:aws:execute-api:eu-central-1:{AWS_ACCOUNT_NUMBER}:bar/*/GET/proxy+" + } + }, + }, + { + "Sid": "FunctionURLAllowPublicAccess", + "Effect": "Allow", + "Principal": "*", + "Action": "lambda:InvokeFunctionUrl", + "Resource": f"arn:aws:lambda:eu-central-1:{AWS_ACCOUNT_NUMBER}:function:foo", + "Condition": { + "StringEquals": {"lambda:FunctionUrlAuthType": "NONE"} + }, + }, + ], + } + + lambda_client.functions = { + "function_name": Function( + name=function_name, + security_groups=[], + arn=function_arn, + region=AWS_REGION_EU_WEST_1, + runtime=function_runtime, + policy=lambda_policy, + ) + } + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_aws_provider(), + ), mock.patch( + "prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible.awslambda_client", + new=lambda_client, + ): + from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible import ( + awslambda_function_not_publicly_accessible, + ) + + check = awslambda_function_not_publicly_accessible() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Lambda function {function_name} has a policy resource-based policy with public access." + ) + assert result[0].resource_id == function_name + assert result[0].resource_arn == function_arn + assert result[0].region == AWS_REGION_EU_WEST_1 diff --git a/tests/providers/aws/services/efs/lib/lib_test.py b/tests/providers/aws/services/efs/lib/lib_test.py deleted file mode 100644 index dc486ba914..0000000000 --- a/tests/providers/aws/services/efs/lib/lib_test.py +++ /dev/null @@ -1,102 +0,0 @@ -from prowler.providers.aws.services.efs.lib.lib import is_public_access_allowed - - -class Test_EFS_lib: - def test__is_public_access_allowed__(self): - statement = { - "Effect": "Allow", - "Principal": "*", - "Action": "elasticfilesystem:ClientMount", - "Resource": "*", - } - assert is_public_access_allowed(statement) - - def test__is_public_access_allowed__with_principal_dict(self): - statement = { - "Effect": "Allow", - "Principal": {"AWS": "*"}, - "Action": "elasticfilesystem:ClientMount", - "Resource": "*", - } - assert is_public_access_allowed(statement) - - def test__is_public_access_allowed__with_secure_conditions(self): - statement = { - "Effect": "Allow", - "Principal": "*", - "Action": "elasticfilesystem:ClientMount", - "Resource": "*", - "Condition": {"Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"}}, - } - assert not is_public_access_allowed(statement) - - def test__is_public_access_allowed__with_secure_conditions_and_allowed_conditions( - self, - ): - statement = { - "Effect": "Allow", - "Principal": "*", - "Action": "elasticfilesystem:ClientMount", - "Resource": "*", - "Condition": { - "Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"}, - "StringEquals": {"aws:SourceOwner": "123456789012"}, - }, - } - assert not is_public_access_allowed(statement) - - def test__is_public_access_allowed__with_secure_conditions_and_allowed_conditions_nested( - self, - ): - statement = { - "Effect": "Allow", - "Principal": "*", - "Action": "elasticfilesystem:ClientMount", - "Resource": "*", - "Condition": { - "Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"}, - "StringEquals": {"aws:SourceOwner": "123456789012"}, - "StringEqualsIfExists": {"aws:SourceVpce": "vpce-1234567890abcdef0"}, - }, - } - assert not is_public_access_allowed(statement) - - def test__is_public_access_allowed__with_secure_conditions_and_allowed_conditions_nested_dict( - self, - ): - statement = { - "Effect": "Allow", - "Principal": "*", - "Action": "elasticfilesystem:ClientMount", - "Resource": "*", - "Condition": { - "Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"}, - "StringEquals": {"aws:SourceOwner": "123456789012"}, - "StringEqualsIfExists": { - "aws:SourceVpce": { - "vpce-1234567890abcdef0": "vpce-1234567890abcdef0" - } - }, - }, - } - assert not is_public_access_allowed(statement) - - def test__is_public_access_allowed__with_secure_conditions_and_allowed_conditions_nested_dict_key( - self, - ): - statement = { - "Effect": "Allow", - "Principal": "*", - "Action": "elasticfilesystem:ClientMount", - "Resource": "*", - "Condition": { - "Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"}, - "StringEquals": {"aws:SourceOwner": "123456789012"}, - "StringEqualsIfExists": { - "aws:SourceVpce": { - "vpce-1234567890abcdef0": "vpce-1234567890abcdef0" - } - }, - }, - } - assert not is_public_access_allowed(statement) diff --git a/tests/providers/aws/services/iam/lib/policy_test.py b/tests/providers/aws/services/iam/lib/policy_test.py index c6be021691..5b62dc61e3 100644 --- a/tests/providers/aws/services/iam/lib/policy_test.py +++ b/tests/providers/aws/services/iam/lib/policy_test.py @@ -1,14 +1,1449 @@ from prowler.providers.aws.services.iam.lib.policy import ( check_admin_access, check_full_service_access, + is_condition_block_restrictive, + is_condition_block_restrictive_organization, is_condition_restricting_from_private_ip, is_policy_cross_account, is_policy_public, ) from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER +TRUSTED_AWS_ACCOUNT_NUMBER = "123456789012" +NON_TRUSTED_AWS_ACCOUNT_NUMBER = "111222333444" + +TRUSTED_ORGANIZATION_ID = "o-123456789012" +NON_TRUSTED_ORGANIZATION_ID = "o-111222333444" + +ALL_ORGS = "*" + class Test_Policy: + # Test lowercase context key name --> aws + def test_condition_parser_string_equals_aws_SourceAccount_list(self): + condition_statement = { + "StringEquals": {"aws:SourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_SourceAccount_list_not_valid(self): + condition_statement = { + "StringEquals": { + "aws:SourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_SourceAccount_str(self): + condition_statement = { + "StringEquals": {"aws:SourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_SourceAccount_str_not_valid(self): + condition_statement = { + "StringEquals": {"aws:SourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_SourceAccount_list(self): + condition_statement = { + "StringLike": {"aws:SourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_SourceAccount_list_not_valid(self): + condition_statement = { + "StringLike": { + "aws:SourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_SourceAccount_str(self): + condition_statement = { + "StringLike": {"aws:SourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_SourceAccount_str_not_valid(self): + condition_statement = { + "StringLike": {"aws:SourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_SourceOwner_str(self): + condition_statement = { + "StringEquals": {"aws:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_SourceOwner_str_not_valid(self): + condition_statement = { + "StringEquals": {"aws:SourceOwner": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_SourceOwner_list(self): + condition_statement = { + "StringEquals": {"aws:SourceOwner": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_SourceOwner_list_not_valid(self): + condition_statement = { + "StringEquals": { + "aws:SourceOwner": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_SourceOwner_list(self): + condition_statement = { + "StringLike": {"aws:SourceOwner": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_SourceOwner_list_not_valid(self): + condition_statement = { + "StringLike": { + "aws:SourceOwner": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_SourceOwner_str(self): + condition_statement = { + "StringLike": {"aws:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_SourceOwner_str_not_valid(self): + condition_statement = { + "StringLike": {"aws:SourceOwner": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_s3_ResourceAccount_list(self): + condition_statement = { + "StringEquals": {"s3:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_s3_ResourceAccount_list_not_valid(self): + condition_statement = { + "StringEquals": { + "s3:ResourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_s3_ResourceAccount_str(self): + condition_statement = { + "StringEquals": {"s3:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_s3_ResourceAccount_str_not_valid(self): + condition_statement = { + "StringEquals": {"s3:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_PrincipalAccount_list(self): + condition_statement = { + "StringEquals": {"aws:PrincipalAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_PrincipalAccount_list_not_valid(self): + condition_statement = { + "StringEquals": { + "aws:PrincipalAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_PrincipalAccount_str(self): + condition_statement = { + "StringEquals": {"aws:PrincipalAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_PrincipalAccount_str_not_valid(self): + condition_statement = { + "StringEquals": {"aws:PrincipalAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_SourceArn_str(self): + condition_statement = { + "StringEquals": { + "aws:SourceArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + } + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_SourceArn_str_not_valid(self): + condition_statement = { + "StringEquals": { + "aws:SourceArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_PrincipalAccount_list(self): + condition_statement = { + "StringLike": {"aws:PrincipalAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_PrincipalAccount_list_not_valid(self): + condition_statement = { + "StringLike": { + "aws:PrincipalAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_PrincipalAccount_str(self): + condition_statement = { + "StringLike": {"aws:PrincipalAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_PrincipalAccount_str_not_valid(self): + condition_statement = { + "StringLike": {"aws:PrincipalAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_aws_SourceArn_list(self): + condition_statement = { + "ArnLike": { + "aws:SourceArn": [ + f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + ] + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_aws_SourceArn_list_not_valid(self): + condition_statement = { + "ArnLike": { + "aws:SourceArn": [ + f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + ] + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_aws_SourceArn_str(self): + condition_statement = { + "ArnLike": { + "aws:SourceArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_aws_SourceArn_str_not_valid(self): + condition_statement = { + "ArnLike": { + "aws:SourceArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_aws_PrincipalArn_list(self): + condition_statement = { + "ArnLike": { + "aws:PrincipalArn": [ + f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + ] + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_aws_PrincipalArn_list_not_valid(self): + condition_statement = { + "ArnLike": { + "aws:PrincipalArn": [ + f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + ] + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_aws_PrincipalArn_str(self): + condition_statement = { + "ArnLike": { + "aws:PrincipalArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_aws_PrincipalArn_str_not_valid(self): + condition_statement = { + "ArnLike": { + "aws:PrincipalArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_aws_SourceArn_list(self): + condition_statement = { + "ArnEquals": { + "aws:SourceArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + ] + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_aws_SourceArn_list_not_valid(self): + condition_statement = { + "ArnEquals": { + "aws:SourceArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + ] + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_aws_SourceArn_str(self): + condition_statement = { + "ArnEquals": { + "aws:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_aws_SourceArn_str_not_valid(self): + condition_statement = { + "ArnEquals": { + "aws:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_aws_PrincipalArn_list(self): + condition_statement = { + "ArnEquals": { + "aws:PrincipalArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + ] + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_aws_PrincipalArn_list_not_valid(self): + condition_statement = { + "ArnEquals": { + "aws:PrincipalArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + ] + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_aws_PrincipalArn_str(self): + condition_statement = { + "ArnEquals": { + "aws:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_aws_PrincipalArn_str_not_valid(self): + condition_statement = { + "ArnEquals": { + "aws:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_SourceArn_list(self): + condition_statement = { + "StringLike": { + "aws:SourceArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + ] + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_SourceArn_list_not_valid(self): + condition_statement = { + "StringLike": { + "aws:SourceArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + ] + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_SourceArn_str(self): + condition_statement = { + "StringLike": { + "aws:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_SourceArn_str_not_valid(self): + condition_statement = { + "StringLike": { + "aws:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_PrincipalArn_list(self): + condition_statement = { + "StringLike": { + "aws:PrincipalArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + ] + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_PrincipalArn_list_not_valid(self): + condition_statement = { + "StringLike": { + "aws:PrincipalArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + ] + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_PrincipalArn_str(self): + condition_statement = { + "StringLike": { + "aws:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_PrincipalArn_str_not_valid(self): + condition_statement = { + "StringLike": { + "aws:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_ResourceAccount_list(self): + condition_statement = { + "StringEquals": {"aws:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_ResourceAccount_list_not_valid(self): + condition_statement = { + "StringEquals": { + "aws:ResourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_ResourceAccount_str(self): + condition_statement = { + "StringEquals": {"aws:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_aws_ResourceAccount_str_not_valid(self): + condition_statement = { + "StringEquals": {"aws:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_ResourceAccount_list(self): + condition_statement = { + "StringLike": {"aws:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_ResourceAccount_list_not_valid(self): + condition_statement = { + "StringLike": { + "aws:ResourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_ResourceAccount_str(self): + condition_statement = { + "StringLike": {"aws:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_aws_ResourceAccount_str_not_valid(self): + condition_statement = { + "StringLike": {"aws:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + # Test uppercase context key name --> AWS + def test_condition_parser_string_equals_AWS_SourceAccount_list(self): + condition_statement = { + "StringEquals": {"AWS:SourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_SourceAccount_list_not_valid(self): + condition_statement = { + "StringEquals": { + "AWS:SourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_SourceAccount_str(self): + condition_statement = { + "StringEquals": {"AWS:SourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_SourceAccount_str_not_valid(self): + condition_statement = { + "StringEquals": {"AWS:SourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_SourceAccount_list(self): + condition_statement = { + "StringLike": {"AWS:SourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_SourceAccount_list_not_valid(self): + condition_statement = { + "StringLike": { + "AWS:SourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_SourceAccount_str(self): + condition_statement = { + "StringLike": {"AWS:SourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_SourceAccount_str_not_valid(self): + condition_statement = { + "StringLike": {"AWS:SourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_SourceOwner_str(self): + condition_statement = { + "StringEquals": {"AWS:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_SourceOwner_str_not_valid(self): + condition_statement = { + "StringEquals": {"AWS:SourceOwner": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_SourceOwner_list(self): + condition_statement = { + "StringEquals": {"AWS:SourceOwner": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_SourceOwner_list_not_valid(self): + condition_statement = { + "StringEquals": { + "AWS:SourceOwner": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_SourceOwner_list(self): + condition_statement = { + "StringLike": {"AWS:SourceOwner": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_SourceOwner_list_not_valid(self): + condition_statement = { + "StringLike": { + "AWS:SourceOwner": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_SourceOwner_str(self): + condition_statement = { + "StringLike": {"AWS:SourceOwner": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_SourceOwner_str_not_valid(self): + condition_statement = { + "StringLike": {"AWS:SourceOwner": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_S3_ResourceAccount_list(self): + condition_statement = { + "StringEquals": {"S3:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_S3_ResourceAccount_list_not_valid(self): + condition_statement = { + "StringEquals": { + "S3:ResourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_S3_ResourceAccount_str(self): + condition_statement = { + "StringEquals": {"S3:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_S3_ResourceAccount_str_not_valid(self): + condition_statement = { + "StringEquals": {"S3:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_PrincipalAccount_list(self): + condition_statement = { + "StringEquals": {"AWS:PrincipalAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_PrincipalAccount_list_not_valid(self): + condition_statement = { + "StringEquals": { + "AWS:PrincipalAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_PrincipalAccount_str(self): + condition_statement = { + "StringEquals": {"AWS:PrincipalAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_PrincipalAccount_str_not_valid(self): + condition_statement = { + "StringEquals": {"AWS:PrincipalAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_PrincipalAccount_list(self): + condition_statement = { + "StringLike": {"AWS:PrincipalAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_PrincipalAccount_list_not_valid(self): + condition_statement = { + "StringLike": { + "AWS:PrincipalAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_PrincipalAccount_str(self): + condition_statement = { + "StringLike": {"AWS:PrincipalAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_PrincipalAccount_str_not_valid(self): + condition_statement = { + "StringLike": {"AWS:PrincipalAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_AWS_SourceArn_list(self): + condition_statement = { + "ArnLike": { + "AWS:SourceArn": [ + f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + ] + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_AWS_SourceArn_list_not_valid(self): + condition_statement = { + "ArnLike": { + "AWS:SourceArn": [ + f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + ] + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_AWS_SourceArn_str(self): + condition_statement = { + "ArnLike": { + "AWS:SourceArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_AWS_SourceArn_str_not_valid(self): + condition_statement = { + "ArnLike": { + "AWS:SourceArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_AWS_PrincipalArn_list(self): + condition_statement = { + "ArnLike": { + "AWS:PrincipalArn": [ + f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + ] + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_AWS_PrincipalArn_list_not_valid(self): + condition_statement = { + "ArnLike": { + "AWS:PrincipalArn": [ + f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + ] + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_AWS_PrincipalArn_str(self): + condition_statement = { + "ArnLike": { + "AWS:PrincipalArn": f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_like_AWS_PrincipalArn_str_not_valid(self): + condition_statement = { + "ArnLike": { + "AWS:PrincipalArn": f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*" + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_AWS_SourceArn_list(self): + condition_statement = { + "ArnEquals": { + "AWS:SourceArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + ] + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_AWS_SourceArn_list_not_valid(self): + condition_statement = { + "ArnEquals": { + "AWS:SourceArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + ] + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_AWS_SourceArn_str(self): + condition_statement = { + "ArnEquals": { + "AWS:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_AWS_SourceArn_str_not_valid(self): + condition_statement = { + "ArnEquals": { + "AWS:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_AWS_PrincipalArn_list(self): + condition_statement = { + "ArnEquals": { + "AWS:PrincipalArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + ] + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_AWS_PrincipalArn_list_not_valid(self): + condition_statement = { + "ArnEquals": { + "AWS:PrincipalArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + ] + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_AWS_PrincipalArn_str(self): + condition_statement = { + "ArnEquals": { + "AWS:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_arn_equals_AWS_PrincipalArn_str_not_valid(self): + condition_statement = { + "ArnEquals": { + "AWS:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_SourceArn_list(self): + condition_statement = { + "StringLike": { + "AWS:SourceArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + ] + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_SourceArn_list_not_valid(self): + condition_statement = { + "StringLike": { + "AWS:SourceArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + ] + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_SourceArn_str(self): + condition_statement = { + "StringLike": { + "AWS:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_SourceArn_str_not_valid(self): + condition_statement = { + "StringLike": { + "AWS:SourceArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_PrincipalArn_list(self): + condition_statement = { + "StringLike": { + "AWS:PrincipalArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + ] + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_PrincipalArn_list_not_valid(self): + condition_statement = { + "StringLike": { + "AWS:PrincipalArn": [ + f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test", + ] + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_PrincipalArn_str(self): + condition_statement = { + "StringLike": { + "AWS:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_PrincipalArn_str_not_valid(self): + condition_statement = { + "StringLike": { + "AWS:PrincipalArn": f"arn:aws:cloudtrail:eu-west-1:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/test" + } + } + + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_ResourceAccount_list(self): + condition_statement = { + "StringEquals": {"AWS:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_ResourceAccount_list_not_valid(self): + condition_statement = { + "StringEquals": { + "AWS:ResourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_ResourceAccount_str(self): + condition_statement = { + "StringEquals": {"AWS:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_equals_AWS_ResourceAccount_str_not_valid(self): + condition_statement = { + "StringEquals": {"AWS:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_ResourceAccount_list(self): + condition_statement = { + "StringLike": {"AWS:ResourceAccount": [TRUSTED_AWS_ACCOUNT_NUMBER]} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_ResourceAccount_list_not_valid(self): + condition_statement = { + "StringLike": { + "AWS:ResourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + } + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_ResourceAccount_str(self): + condition_statement = { + "StringLike": {"AWS:ResourceAccount": TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_string_like_AWS_ResourceAccount_str_not_valid(self): + condition_statement = { + "StringLike": {"AWS:ResourceAccount": NON_TRUSTED_AWS_ACCOUNT_NUMBER} + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_two_lists_unrestrictive(self): + condition_statement = { + "StringLike": { + "AWS:ResourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + }, + "ArnLike": { + "AWS:SourceArn": [ + f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + ] + }, + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_two_lists_both_restrictive(self): + condition_statement = { + "StringLike": { + "AWS:ResourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + ] + }, + "ArnLike": { + "AWS:SourceArn": [ + f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + ] + }, + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_two_lists_first_restrictive(self): + condition_statement = { + "StringLike": { + "AWS:ResourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + ] + }, + "ArnLike": { + "AWS:SourceArn": [ + f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + f"arn:aws:cloudtrail:*:{NON_TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + ] + }, + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_two_lists_second_restrictive(self): + condition_statement = { + "StringLike": { + "AWS:ResourceAccount": [ + TRUSTED_AWS_ACCOUNT_NUMBER, + NON_TRUSTED_AWS_ACCOUNT_NUMBER, + ] + }, + "ArnLike": { + "AWS:SourceArn": [ + f"arn:aws:cloudtrail:*:{TRUSTED_AWS_ACCOUNT_NUMBER}:trail/*", + ] + }, + } + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER + ) + + def test_condition_parser_allowing_cross_account_with_invalid_block(self): + condition_statement = { + "StringLike": { + "s3:prefix": [ + "home/", + ] + }, + } + assert not is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER, True + ) + + def test_condition_parser_string_equals_vpc(self): + condition_statement = {"StringEquals": {"aws:SourceVpc": "vpc-123456"}} + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER, True + ) + + def test_condition_parser_string_equals_vpc_list(self): + condition_statement = {"StringEquals": {"aws:sourcevpc": ["vpc-123456"]}} + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER, True + ) + + def test_condition_parser_string_equals_vpc_list_not_valid(self): + condition_statement = { + "StringEquals": {"aws:SourceVpc": ["vpc-123456", "vpc-654321"]} + } + + assert is_condition_block_restrictive( + condition_statement, TRUSTED_AWS_ACCOUNT_NUMBER, True + ) + + def test_condition_parser_string_equals_aws_PrincipalOrgID_list(self): + condition_statement = { + "StringEquals": {"aws:PrincipalOrgID": [TRUSTED_ORGANIZATION_ID]} + } + assert is_condition_block_restrictive_organization(condition_statement) + + def test_condition_parser_string_equals_aws_PrincipalOrgID_list_multiple_items( + self, + ): + condition_statement = { + "StringEquals": { + "aws:PrincipalOrgID": [ + TRUSTED_ORGANIZATION_ID, + NON_TRUSTED_ORGANIZATION_ID, + ] + } + } + assert is_condition_block_restrictive_organization(condition_statement) + + def test_condition_parser_string_equals_aws_PrincipalOrgID_str(self): + condition_statement = { + "StringEquals": {"aws:PrincipalOrgID": TRUSTED_ORGANIZATION_ID} + } + assert is_condition_block_restrictive_organization(condition_statement) + + def test_condition_parser_string_equals_aws_All_Orgs_list_multiple_items( + self, + ): + condition_statement = { + "StringEquals": { + "aws:PrincipalOrgID": [ + TRUSTED_ORGANIZATION_ID, + ALL_ORGS, + ] + } + } + assert not is_condition_block_restrictive_organization(condition_statement) + + def test_condition_parser_string_equals_aws_All_Orgs_str(self): + condition_statement = {"StringEquals": {"aws:PrincipalOrgID": ALL_ORGS}} + assert not is_condition_block_restrictive_organization(condition_statement) + def test_policy_allows_cross_account_access_with_root_and_wildcard_principal(self): policy_allow_root_and_wildcard_principal = { "Statement": [ @@ -67,7 +1502,9 @@ class Test_Policy: } ] } - assert is_policy_public(policy_allow_wildcard_principal) + assert is_policy_public( + policy_allow_wildcard_principal, not_allowed_actions=["s3:*"] + ) def test_policy_allows_public_access_with_aws_wildcard_principal(self): policy_allow_aws_wildcard_principal = { @@ -80,7 +1517,9 @@ class Test_Policy: } ] } - assert is_policy_public(policy_allow_aws_wildcard_principal) + assert is_policy_public( + policy_allow_aws_wildcard_principal, not_allowed_actions=["s3:*"] + ) def test_policy_does_not_allow_public_access_with_specific_aws_principal(self): policy_allow_specific_aws_principal = { @@ -279,6 +1718,155 @@ class Test_Policy: } assert not is_condition_restricting_from_private_ip(condition_from_invalid_ip) + def test__is_policy_public__(self): + policy = { + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": "elasticfilesystem:ClientMount", + "Resource": "*", + } + ] + } + assert is_policy_public( + policy, not_allowed_actions=["elasticfilesystem:ClientMount"] + ) + + def test__is_policy_public__with_principal_dict(self): + policy = { + "Statement": [ + { + "Effect": "Allow", + "Principal": {"AWS": "*"}, + "Action": "elasticfilesystem:ClientMount", + "Resource": "*", + } + ] + } + assert is_policy_public( + policy, not_allowed_actions=["elasticfilesystem:ClientMount"] + ) + + def test__is_policy_public__with_secure_conditions_and_allowed_conditions( + self, + ): + policy = { + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": "elasticfilesystem:ClientMount", + "Resource": "*", + "Condition": { + "Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"}, + "StringEquals": {"aws:SourceOwner": "123456789012"}, + }, + } + ] + } + assert not is_policy_public(policy) + + def test__is_policy_public__with_secure_conditions_and_allowed_conditions_nested( + self, + ): + policy = { + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": "elasticfilesystem:ClientMount", + "Resource": "*", + "Condition": { + "Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"}, + "StringEquals": {"aws:SourceOwner": "123456789012"}, + "StringEqualsIfExists": { + "aws:SourceVpce": "vpce-1234567890abcdef0" + }, + }, + } + ] + } + assert not is_policy_public(policy) + + def test__is_policy_public__with_secure_conditions_and_allowed_conditions_nested_dict( + self, + ): + policy = { + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": "elasticfilesystem:ClientMount", + "Resource": "*", + "Condition": { + "Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"}, + "StringEquals": {"aws:SourceOwner": "123456789012"}, + "StringEqualsIfExists": { + "aws:SourceVpce": { + "vpce-1234567890abcdef0": "vpce-1234567890abcdef0" + } + }, + }, + } + ] + } + assert not is_policy_public(policy) + + def test__is_policy_public__with_secure_conditions_and_allowed_conditions_nested_dict_key( + self, + ): + policy = { + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": "elasticfilesystem:ClientMount", + "Resource": "*", + "Condition": { + "Bool": {"elasticfilesystem:AccessedViaMountTarget": "true"}, + "StringEquals": {"aws:SourceOwner": "123456789012"}, + "StringEqualsIfExists": { + "aws:SourceVpce": { + "vpce-1234567890abcdef0": "vpce-1234567890abcdef0" + } + }, + }, + } + ] + } + assert not is_policy_public(policy) + + def test__is_policy_public_with_action_wildcard( + self, + ): + policy = { + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": "elasticfilesystem:*", + "Resource": "*", + } + ] + } + assert is_policy_public(policy) + + def test__is_policy_public_allowing_all_actions( + self, + ): + policy = { + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": "*", + "Resource": "*", + } + ] + } + assert is_policy_public(policy) + def test_check_admin_access(self): policy = { "Version": "2012-10-17",