Exemple #1
0
    def __init__(self, policy_details, exclusions=DEFAULT_EXCLUSIONS):
        self.policy_details = []
        if not isinstance(exclusions, Exclusions):
            raise Exception(
                "The exclusions provided is not an Exclusions type object. "
                "Please supply an Exclusions object and try again."
            )
        self.exclusions = exclusions

        for policy_detail in policy_details:
            this_policy_name = policy_detail.get("PolicyName")
            this_policy_id = policy_detail.get("PolicyId")
            this_policy_path = policy_detail.get("Path")
            # Always exclude the AWS service role policies
            if (
                is_name_excluded(this_policy_path, "aws-service-role*")
                or is_name_excluded(this_policy_path, "/aws-service-role*")
            ):
                logger.debug("The %s Policy with the policy ID %s is excluded because it is "
                             "an immutable AWS Service role with a path of %s",
                             this_policy_name, this_policy_id, this_policy_path)
                continue
            # Exclude the managed policies
            if (
                exclusions.is_policy_excluded(this_policy_name)
                or exclusions.is_policy_excluded(this_policy_id)
                or exclusions.is_policy_excluded(this_policy_path)
            ):
                logger.debug("The %s Managed Policy with the policy ID %s and %s path is excluded.",
                             this_policy_name, this_policy_id, this_policy_path)
                continue
            self.policy_details.append(ManagedPolicy(policy_detail, exclusions))
Exemple #2
0
    def __init__(
        self,
        policy_details: List[Dict[str, Any]],
        exclusions: Exclusions = DEFAULT_EXCLUSIONS,
        flag_conditional_statements: bool = False,
        flag_resource_arn_statements: bool = False,
    ) -> None:
        self.policy_details = []
        if not isinstance(exclusions, Exclusions):
            raise Exception(
                "The exclusions provided is not an Exclusions type object. "
                "Please supply an Exclusions object and try again.")
        self.exclusions = exclusions
        self.flag_conditional_statements = flag_conditional_statements
        self.flag_resource_arn_statements = flag_resource_arn_statements

        for policy_detail in policy_details:
            this_policy_name = policy_detail["PolicyName"]
            this_policy_id = policy_detail["PolicyId"]
            this_policy_path = policy_detail["Path"]
            # Always exclude the AWS service role policies
            if is_name_excluded(this_policy_path,
                                "aws-service-role*") or is_name_excluded(
                                    this_policy_path, "/aws-service-role*"):
                logger.debug(
                    "The %s Policy with the policy ID %s is excluded because it is "
                    "an immutable AWS Service role with a path of %s",
                    this_policy_name,
                    this_policy_id,
                    this_policy_path,
                )
                continue
            # Exclude the managed policies
            if (exclusions.is_policy_excluded(this_policy_name)
                    or exclusions.is_policy_excluded(this_policy_id)
                    or exclusions.is_policy_excluded(this_policy_path)):
                logger.debug(
                    "The %s Managed Policy with the policy ID %s and %s path is excluded.",
                    this_policy_name,
                    this_policy_id,
                    this_policy_path,
                )
                continue
            self.policy_details.append(
                ManagedPolicy(policy_detail,
                              exclusions=exclusions,
                              flag_resource_arn_statements=self.
                              flag_resource_arn_statements,
                              flag_conditional_statements=self.
                              flag_conditional_statements))
 def _is_excluded(self, exclusions):
     """Determine whether the principal name or principal ID is excluded"""
     return bool(
         exclusions.is_principal_excluded(self.role_name, "Role")
         or exclusions.is_principal_excluded(self.role_id, "Role")
         or exclusions.is_principal_excluded(self.path, "Role")
         or is_name_excluded(self.path, "/aws-service-role*"))
 def _is_excluded(self, exclusions):
     """Determine whether the policy name or policy ID is excluded"""
     return bool(
         exclusions.is_policy_excluded(self.policy_name)
         or exclusions.is_policy_excluded(self.policy_id)
         or exclusions.is_policy_excluded(self.path)
         or is_name_excluded(self.path, "/aws-service-role*"))
    def __init__(
        self,
        role_details: List[Dict[str, Any]],
        policy_details: ManagedPolicyDetails,
        exclusions: Exclusions = DEFAULT_EXCLUSIONS,
    ) -> None:
        self.roles = []

        if not isinstance(exclusions, Exclusions):
            raise Exception(
                "For exclusions, please provide an object of the Exclusions type"
            )
        self.exclusions = exclusions

        for role_detail in role_details:
            this_role_name = role_detail.get("RoleName")
            this_role_path = role_detail["Path"]
            if is_name_excluded(this_role_path, "/aws-service-role*"):
                logger.debug(
                    "%s role is excluded because it is an immutable AWS Service role with a path of %s",
                    this_role_name,
                    this_role_path,
                )
            else:
                self.roles.append(
                    RoleDetail(role_detail, policy_details, exclusions))
Exemple #6
0
 def is_principal_excluded(self, exclusions=DEFAULT_EXCLUSIONS):
     """According to the exclusions configuration, determine whether or not to skip the Principal according
     to their name."""
     decision = False
     name = get_resource_path_from_arn(self.arn)
     if self.principal_type == "User":
         if is_name_excluded(name, exclusions.users):
             print(f"\tExcluded user: {name}")
             decision = True
     if self.principal_type == "Group":
         if is_name_excluded(name, exclusions.groups):
             print(f"\tExcluded group: {name}")
             decision = True
     if self.principal_type == "Role":
         if is_name_excluded(name, exclusions.roles):
             print(f"\tExcluded role: {name}")
             decision = True
     return decision
 def is_principal_excluded(self, exclusions_cfg=DEFAULT_EXCLUSIONS_CONFIG):
     """According to the exclusions configuration, determine whether or not to skip the Principal according
     to their name."""
     decision = False
     if self.principal_type == "User":
         if is_name_excluded(
             get_resource_path_from_arn(self.arn), exclusions_cfg.get("users")
         ):
             decision = True
     if self.principal_type == "Group":
         if is_name_excluded(
             get_resource_path_from_arn(self.arn), exclusions_cfg.get("groups")
         ):
             decision = True
     if self.principal_type == "Role":
         if is_name_excluded(
             get_resource_path_from_arn(self.arn), exclusions_cfg.get("roles")
         ):
             decision = True
     return decision
Exemple #8
0
 def _actions(self, actions):
     results = []
     if self.always_exclude_actions:
         for action in actions:
             if is_name_excluded(action.lower(), self.always_exclude_actions):
                 # logger.info("Excluded action: %s" % action)
                 pass
             else:
                 results.append(action)
         return results
     else:
         return actions
 def _actions(self, actions):
     results = []
     if self.always_exclude_actions:
         for action in actions:
             if is_name_excluded(action.lower(),
                                 self.always_exclude_actions):
                 pass  # pragma: no cover
             else:
                 results.append(action)
         return results
     else:
         return actions
Exemple #10
0
    def scan_policy_details(self,
                            exclusions_cfg=DEFAULT_EXCLUSIONS_CONFIG,
                            modify_only=True):
        """Scan the PolicyDetails block of the account authorization details output."""
        excluded_actions = exclusions_cfg.get("exclude-actions", None)

        for policy in self.policies.policy_details:
            print(f"Scanning policy: {policy.policy_name}")
            always_include_actions = exclusions_cfg.get("include-actions")
            actions_missing_resource_constraints = []
            if is_name_excluded(policy.policy_name,
                                exclusions_cfg.get("policies")):
                print(f"\tExcluded policy name: {policy.policy_name}")
            elif is_name_excluded(policy.full_policy_path,
                                  exclusions_cfg.get("policies")):
                print(f"\tExcluded policy path: {policy.full_policy_path}")
            else:
                for statement in policy.policy_document.statements:
                    if modify_only:
                        if statement.effect == "Allow":
                            actions_missing_resource_constraints.extend(
                                statement.
                                missing_resource_constraints_for_modify_actions(
                                    always_include_actions))
                    else:
                        if statement.effect == "Allow":
                            actions_missing_resource_constraints.extend(
                                statement.missing_resource_constraints)
                if actions_missing_resource_constraints:
                    actions_missing_resource_constraints = list(
                        dict.fromkeys(actions_missing_resource_constraints)
                    )  # remove duplicates
                    actions_missing_resource_constraints.sort()
                    finding = Finding(
                        policy_name=policy.policy_name,
                        arn=policy.arn,
                        actions=actions_missing_resource_constraints,
                        policy_document=policy.policy_document,
                        always_exclude_actions=excluded_actions)
                    self.findings.add(finding)
def scan_policy(policy_json, policy_name, exclusions_cfg=DEFAULT_EXCLUSIONS_CONFIG):
    """
    Scan a policy document for missing resource constraints.

    :param policy_json: The AWS IAM policy document.
    :param exclusions_cfg: Defaults to the embedded exclusions file, which has no effect here.
    :param policy_name: The name of the IAM policy. Defaults to the filename when used from command line.
    :return:
    """
    policy_document = PolicyDocument(policy_json)
    actions_missing_resource_constraints = []

    # EXCLUDED ACTIONS - actions to exclude if they are false positives
    excluded_actions = exclusions_cfg.get("exclude-actions", None)
    if excluded_actions == [""]:
        excluded_actions = None

    # convert to lowercase for comparison purposes
    # some weird if/else logic to reduce loops and improve performance slightly
    if excluded_actions:
        excluded_actions = [x.lower() for x in excluded_actions]

    always_include_actions = exclusions_cfg.get("include-actions")
    findings = Findings()

    for statement in policy_document.statements:
        if statement.effect == "Allow":
            actions_missing_resource_constraints.extend(
                statement.missing_resource_constraints_for_modify_actions(
                    always_include_actions
                )
            )
    if actions_missing_resource_constraints:
        results_placeholder = []
        for action in actions_missing_resource_constraints:
            if excluded_actions:
                if not is_name_excluded(action.lower(), excluded_actions):
                    results_placeholder.append(action)  # pragma: no cover
            else:
                results_placeholder.append(action)
        actions_missing_resource_constraints = list(
            dict.fromkeys(results_placeholder)
        )  # remove duplicates
        actions_missing_resource_constraints.sort()
        finding = Finding(
            policy_name=policy_name,
            arn=policy_name,
            actions=actions_missing_resource_constraints,
            policy_document=policy_document,
        )
        findings.add(finding)
    return findings.json
Exemple #12
0
 def permissions_management_actions_without_constraints(self):
     """Return a list of actions that could cause resource exposure via actions at the 'Permissions management'
     access level, if applicable."""
     results = []
     if self.always_exclude_actions:
         for action in self.policy_document.permissions_management_without_constraints:
             if is_name_excluded(action.lower(), self.always_exclude_actions):
                 pass
             else:
                 results.append(action)
         return results
     else:
         return self.policy_document.permissions_management_without_constraints
Exemple #13
0
    def scan_principal_type_details(
        self,
        principal_type_detail_list,
        exclusions_cfg=DEFAULT_EXCLUSIONS_CONFIG,
        modify_only=True,
    ):
        """Scan the UserDetailList, GroupDetailList, or RoleDetailList blocks of the account authorization details output."""
        excluded_actions = exclusions_cfg.get("exclude-actions", None)

        for principal in principal_type_detail_list.principals:
            always_include_actions = exclusions_cfg.get("include-actions")
            print(f"Scanning {principal.principal_type}: {principal.name}")
            for policy in principal.policy_list:
                print(f"\tScanning Policy: {policy['PolicyName']}")

                if is_name_excluded(policy["PolicyName"],
                                    exclusions_cfg.get("policies")):
                    print(f"\tExcluded policy name: {policy['PolicyName']}")
                elif principal.is_principal_excluded(exclusions_cfg):
                    print(f"\tExcluded principal name: {principal.name}")
                else:
                    policy_document = policy["PolicyDocument"]
                    actions_missing_resource_constraints = []
                    for statement in policy_document.statements:
                        if modify_only:
                            if statement.effect == "Allow":
                                actions_missing_resource_constraints.extend(
                                    statement.
                                    missing_resource_constraints_for_modify_actions(
                                        always_include_actions))
                        else:
                            if statement.effect == "Allow":
                                actions_missing_resource_constraints.extend(
                                    statement.missing_resource_constraints)
                    if actions_missing_resource_constraints:
                        finding = Finding(
                            policy_name=policy["PolicyName"],
                            arn=principal.arn,
                            actions=actions_missing_resource_constraints,
                            policy_document=policy["PolicyDocument"],
                            assume_role_policy_document=principal.
                            assume_role_policy_document,
                            always_exclude_actions=excluded_actions)
                        self.findings.add(finding)
Exemple #14
0
    def __init__(
        self,
        role_details: List[Dict[str, Any]],
        policy_details: ManagedPolicyDetails,
        exclusions: Exclusions = DEFAULT_EXCLUSIONS,
        flag_conditional_statements: bool = False,
        flag_resource_arn_statements: bool = False,
    ) -> None:
        self.roles = []

        if not isinstance(exclusions, Exclusions):
            raise Exception(
                "For exclusions, please provide an object of the Exclusions type"
            )
        self.exclusions = exclusions
        # Fix Issue #254 - Allow flagging risky actions even when there are resource constraints
        self.flag_conditional_statements = flag_conditional_statements
        self.flag_resource_arn_statements = flag_resource_arn_statements

        for role_detail in role_details:
            this_role_name = role_detail.get("RoleName")
            this_role_path = role_detail["Path"]
            if is_name_excluded(this_role_path, "/aws-service-role*"):
                logger.debug(
                    "%s role is excluded because it is an immutable AWS Service role with a path of %s",
                    this_role_name,
                    this_role_path,
                )
            else:
                self.roles.append(
                    RoleDetail(role_detail,
                               policy_details,
                               exclusions=exclusions,
                               flag_conditional_statements=self.
                               flag_conditional_statements,
                               flag_resource_arn_statements=self.
                               flag_resource_arn_statements))
Exemple #15
0
 def test_exclusions_suffix_match(self):
     """test_exclusions_suffix_match: Test exclusions function with suffix wildcard logic."""
     exclusions_list = ["*ish"]
     policy_name = "Secure-ish"
     result = is_name_excluded(policy_name, exclusions_list)
     self.assertTrue(result)
Exemple #16
0
 def test_exclusions_prefix_match(self):
     """test_exclusions_prefix_match: Test exclusions function with prefix wildcard logic."""
     exclusions_list = ["ThePerfectManDoesntExi*"]
     policy_name = "ThePerfectManDoesntExist"
     result = is_name_excluded(policy_name, exclusions_list)
     self.assertTrue(result)
Exemple #17
0
 def test_exclusions_exact_match(self):
     """test_exclusions_exact_match: If there is an exact match in the exclusions list"""
     exclusions_list = ["Beyonce"]
     policy_name = "Beyonce"
     result = is_name_excluded(policy_name, exclusions_list)
     self.assertTrue(result)