コード例 #1
0
    def test_findings_add_list(self):
        """output.findings.findings.add: Make sure the add function works with adding it as a list"""
        test_policy = {
            "Version":
            "2012-10-17",
            "Statement": [{
                "Effect": "Allow",
                "Action": ["s3:GetObject"],
                "Resource": "*"
            }]
        }
        policy_document = PolicyDocument(test_policy)
        finding_1 = Finding(
            policy_name="MyPolicy",
            arn="arn:aws:iam::123456789012:group/SNSNotifications",
            actions=["s3:GetObject"],
            policy_document=policy_document)
        finding_2 = Finding(policy_name="MyPolicy",
                            arn="arn:aws:iam::aws:policy/BadAWSManagedPolicy",
                            actions=["s3:GetObject"],
                            policy_document=policy_document)

        findings = Findings()
        findings.add([finding_1, finding_2])
        result = findings.json
        self.assertTrue(len(result) == 2)
コード例 #2
0
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
コード例 #3
0
class AuthorizationDetails:
    """
    Represents the entire JSON file generated by the aws iam get-account-authorization-details command.
    """
    def __init__(self, auth_json):
        self.auth_json = auth_json
        self.policies = PolicyDetails(auth_json.get("Policies", None))
        self.user_detail_list = PrincipalTypeDetails(
            auth_json.get("UserDetailList", None))
        self.group_detail_list = PrincipalTypeDetails(
            auth_json.get("GroupDetailList", None))
        self.role_detail_list = PrincipalTypeDetails(
            auth_json.get("RoleDetailList", None))
        self.findings = Findings()
        self.customer_managed_policies_in_use = self._customer_managed_policies_in_use(
        )
        self.aws_managed_policies_in_use = self._aws_managed_policies_in_use()

    def _aws_managed_policies_in_use(self):
        aws_managed_policies = []
        for policy in self.policies.policy_details:
            if "arn:aws:iam::aws:" in policy.arn:
                aws_managed_policies.append(policy.policy_name)
        # Policies attached to groups
        for principal in self.group_detail_list.principals:
            for attached_managed_policy in principal.attached_managed_policies:
                if "arn:aws:iam::aws:" in attached_managed_policy.get(
                        "PolicyArn"):
                    aws_managed_policies.append(
                        attached_managed_policy.get("PolicyName"))
        # Policies attached to users
        for principal in self.user_detail_list.principals:
            for attached_managed_policy in principal.attached_managed_policies:
                if "arn:aws:iam::aws:" in attached_managed_policy.get(
                        "PolicyArn"):
                    aws_managed_policies.append(
                        attached_managed_policy.get("PolicyName"))
        # Policies attached to roles
        for principal in self.role_detail_list.principals:
            for attached_managed_policy in principal.attached_managed_policies:
                if "arn:aws:iam::aws:" in attached_managed_policy.get(
                        "PolicyArn"):
                    aws_managed_policies.append(
                        attached_managed_policy.get("PolicyName"))

        return aws_managed_policies

    def _customer_managed_policies_in_use(self):
        customer_managed_policies = []
        for policy in self.policies.policy_details:
            if "arn:aws:iam::aws:" not in policy.arn:
                customer_managed_policies.append(policy.policy_name)
        # Policies attached to groups
        for principal in self.group_detail_list.principals:
            for attached_managed_policy in principal.attached_managed_policies:
                if "arn:aws:iam::aws:" not in attached_managed_policy.get(
                        "PolicyArn"):
                    customer_managed_policies.append(
                        attached_managed_policy.get("PolicyName"))
        # Policies attached to users
        for principal in self.user_detail_list.principals:
            for attached_managed_policy in principal.attached_managed_policies:
                if "arn:aws:iam::aws:" not in attached_managed_policy.get(
                        "PolicyArn"):
                    customer_managed_policies.append(
                        attached_managed_policy.get("PolicyName"))
        # Policies attached to roles
        for principal in self.role_detail_list.principals:
            for attached_managed_policy in principal.attached_managed_policies:
                if "arn:aws:iam::aws:" not in attached_managed_policy.get(
                        "PolicyArn"):
                    customer_managed_policies.append(
                        attached_managed_policy.get("PolicyName"))

        return customer_managed_policies

    @property
    def groups(self):
        """A list of the group names in the account, according to the account authorization details."""
        group_names = []
        for principal in self.group_detail_list.principals:
            group_names.append(principal.name)
        return group_names

    @property
    def roles(self):
        """A list of the role names in the account, according to the account authorization details."""
        role_names = []
        for principal in self.role_detail_list.principals:
            role_names.append(principal.name)
        return role_names

    @property
    def users(self):
        """A list of the user names in the account, according to the account authorization details."""
        user_names = []
        for principal in self.user_detail_list.principals:
            user_names.append(principal.name)
        return user_names

    @property
    def principals(self):
        """Get a list of PrincipalDetail objects for all principals - Users, Groups, or Roles - in the account."""
        all_principals = []
        # Users
        for principal in self.user_detail_list.principals:
            all_principals.append(principal)
        # Groups
        for principal in self.group_detail_list.principals:
            all_principals.append(principal)
        # Roles
        for principal in self.role_detail_list.principals:
            all_principals.append(principal)
        return all_principals

    @property
    def principal_policy_mapping(self):
        """
        Returns a mapping of principals vs the policies that they are attached to - either inline or managed.
        """
        principal_policy_mapping = []

        for principal in self.principals:
            # Inline Policies
            if principal.inline_principal_policies:
                for inline_policy in principal.inline_principal_policies:
                    entry = dict(Principal=principal.name,
                                 Type=principal.principal_type,
                                 PolicyType="Inline",
                                 ManagedBy="Customer",
                                 PolicyName=inline_policy.get("PolicyName"),
                                 Comment=None)
                    principal_policy_mapping.append(entry)
            # AttachedManagedPolicies
            if principal.attached_managed_policies:
                for attached_managed_policy in principal.attached_managed_policies:
                    if "arn:aws:iam::aws:" in attached_managed_policy.get(
                            "PolicyArn"):
                        managed_by = "AWS"
                    else:
                        managed_by = "Customer"
                    entry = dict(
                        Principal=principal.name,
                        Type=principal.principal_type,
                        PolicyType="Managed",
                        ManagedBy=managed_by,
                        PolicyName=attached_managed_policy.get("PolicyName"),
                        Comment=None,
                    )
                    principal_policy_mapping.append(entry)

            # While users might have inline policies or managed policies,
            # their findings will need to reflect their group membership findings as well.
            # So we need to run that loop again, finding the data for their groups and adding it.
            if principal.principal_type == "User":
                group_memberships = principal.group_member
                for group_membership in group_memberships:
                    for some_principal in self.principals:
                        if some_principal.principal_type == "Group" and some_principal.name == group_membership:
                            if some_principal.inline_principal_policies:
                                for inline_policy in some_principal.inline_principal_policies:
                                    entry = dict(Principal=principal.name,
                                                 Type=principal.principal_type,
                                                 PolicyType="Inline",
                                                 ManagedBy="Customer",
                                                 PolicyName=inline_policy.get(
                                                     "PolicyName"),
                                                 Comment="Group Membership")
                                    principal_policy_mapping.append(entry)
                            # AttachedManagedPolicies
                            if some_principal.attached_managed_policies:
                                for attached_managed_policy in some_principal.attached_managed_policies:
                                    if "arn:aws:iam::aws:" in attached_managed_policy.get(
                                            "PolicyArn"):
                                        managed_by = "AWS"
                                    else:
                                        managed_by = "Customer"
                                    entry = dict(
                                        Principal=principal.name,
                                        Type=principal.principal_type,
                                        PolicyType="Managed",
                                        ManagedBy=managed_by,
                                        PolicyName=attached_managed_policy.get(
                                            "PolicyName"),
                                        Comment="Group Membership")
                                    principal_policy_mapping.append(entry)
        # Sort it
        principal_policy_mapping = sorted(principal_policy_mapping,
                                          key=itemgetter(
                                              "Type", "Principal",
                                              "PolicyType", "PolicyName"))
        return principal_policy_mapping

    def missing_resource_constraints(self,
                                     exclusions_cfg=DEFAULT_EXCLUSIONS_CONFIG,
                                     modify_only=True):
        """Scan the account authorization details for missing resource constraints."""
        print("-----USERS-----")
        self.scan_principal_type_details(self.user_detail_list, exclusions_cfg,
                                         modify_only)
        print("-----GROUPS-----")
        self.scan_principal_type_details(self.group_detail_list,
                                         exclusions_cfg, modify_only)
        print("-----ROLES-----")
        self.scan_principal_type_details(self.role_detail_list, exclusions_cfg,
                                         modify_only)
        print("-----POLICIES-----")
        self.scan_policy_details(exclusions_cfg, modify_only)
        return self.findings.json

    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_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)