Esempio n. 1
0
def _get_permissions_in_policy(policy_dict, warn_unknown_perms=False):
    """
    Given a set of policies for a role, return a set of all allowed permissions

    Args:
        policy_dict
        warn_unknown_perms

    Returns
        tuple
        set - all permissions allowed by the policies
        set - all permisisons allowed by the policies not marked with STATEMENT_SKIP_SID
    """
    total_permissions = set()
    eligible_permissions = set()

    for policy_name, policy in list(policy_dict.items()):
        policy = expand_policy(policy=policy, expand_deny=False)
        for statement in policy.get("Statement"):
            if statement["Effect"].lower() == "allow":
                total_permissions = total_permissions.union(
                    get_actions_from_statement(statement))
                if not ("Sid" in statement
                        and statement["Sid"].startswith(STATEMENT_SKIP_SID)):
                    # No Sid
                    # Sid exists, but doesn't start with STATEMENT_SKIP_SID
                    eligible_permissions = eligible_permissions.union(
                        get_actions_from_statement(statement))

    weird_permissions = total_permissions.difference(all_permissions)
    if weird_permissions and warn_unknown_perms:
        LOGGER.warning(
            "Unknown permissions found: {}".format(weird_permissions))

    return total_permissions, eligible_permissions
Esempio n. 2
0
 def test_get_actions_from_statement(self):
     statement = {
         "Action": "ec2:thispermissiondoesntexist",
         "NotAction": list(all_permissions),
         "Resource": "*",
         "Effect": "Allow"
     }
     expected_result = {"ec2:thispermissiondoesntexist"}
     result = get_actions_from_statement(statement)
     self.assertEqual(result, expected_result)
     get_actions_from_statement(dict(NotAction="abc"))
Esempio n. 3
0
def _get_permissions_in_policy(policy_dict, warn_unknown_perms=False):
    """
    Given a set of policies for a role, return a set of all allowed permissions

    Args:
        policy_dict
        warn_unknown_perms

    Returns
        set - all permissions allowed by the policies
    """
    permissions = set()

    for policy_name, policy in policy_dict.items():
        policy = expand_policy(policy=policy, expand_deny=False)
        for statement in policy.get('Statement'):
            if statement['Effect'].lower() == 'allow':
                permissions = permissions.union(
                    get_actions_from_statement(statement))

    weird_permissions = permissions.difference(all_permissions)
    if weird_permissions and warn_unknown_perms:
        LOGGER.warn('Unknown permissions found: {}'.format(weird_permissions))

    return permissions
Esempio n. 4
0
def _get_role_permissions(role):
    """
    Expand the most recent version of policies from a role to produce a list of all the permissions that are allowed
    (permission is included in one or more statements that is allowed).  To perform expansion the policyuniverse
    library is used. The result is a list of all of the individual permissions that are allowed in any of the
    statements. If our resultant list contains any permissions that aren't listed in the master list of permissions
    we'll add them to our global list of WEIRD permissions to warn about later.

    Args:
        role (Role): The role object that we're getting a list of permissions for

    Returns:
        set: A set of permissions that the role has policies that allow
    """
    permissions = set()
    for policy_name, policy in role.policies[-1]['Policy'].items():
        policy = expand_policy(policy=policy, expand_deny=False)
        for statement in policy.get('Statement'):
            if statement['Effect'].lower() == 'allow':
                permissions = permissions.union(
                    get_actions_from_statement(statement))

    global WEIRD
    weird_permissions = permissions.difference(all_permissions)
    if weird_permissions:
        WEIRD = WEIRD.union(weird_permissions)

    return permissions
Esempio n. 5
0
def _get_role_permissions(role, warn_unknown_perms=False):
    """
    Expand the most recent version of policies from a role to produce a list of all the permissions that are allowed
    (permission is included in one or more statements that is allowed).  To perform expansion the policyuniverse
    library is used. The result is a list of all of the individual permissions that are allowed in any of the
    statements. If our resultant list contains any permissions that aren't listed in the master list of permissions
    we'll raise an exception with the set of unknown permissions found.

    Args:
        role (Role): The role object that we're getting a list of permissions for

    Returns:
        set: A set of permissions that the role has policies that allow
    """
    permissions = set()

    for policy_name, policy in role.policies[-1]['Policy'].items():
        policy = expand_policy(policy=policy, expand_deny=False)
        for statement in policy.get('Statement'):
            if statement['Effect'].lower() == 'allow':
                permissions = permissions.union(
                    get_actions_from_statement(statement))

    weird_permissions = permissions.difference(all_permissions)
    if weird_permissions and warn_unknown_perms:
        LOGGER.warn('Unknown permissions found: {}'.format(weird_permissions))

    return permissions
Esempio n. 6
0
def _get_repoed_policy(policies, repoable_permissions):
    """
    This function contains the logic to rewrite the policy to remove any repoable permissions. To do so we:
      - Iterate over role policies
      - Iterate over policy statements
      - Skip Deny statements
      - Remove any actions that are in repoable_permissions
      - Remove any statements that now have zero actions
      - Remove any policies that now have zero statements

    Args:
        policies (dict): All of the inline policies as a dict with name and policy contents
        repoable_permissions (set): A set of all of the repoable permissions for policies

    Returns:
        dict: The rewritten set of all inline policies
        list: Any policies that are now empty as a result of the rewrites
    """
    # work with our own copy; don't mess with the CACHE copy.
    role_policies = copy.deepcopy(policies)

    empty_policies = []
    for policy_name, policy in role_policies.items():
        # list of indexes in the policy that are empty
        empty_statements = []

        if type(policy['Statement']) is dict:
            policy['Statement'] = [policy['Statement']]

        for idx, statement in enumerate(policy['Statement']):
            if statement['Effect'].lower() == 'allow':
                statement_actions = get_actions_from_statement(statement)
                statement_actions = statement_actions.difference(
                    repoable_permissions)

                # get_actions_from_statement has already inverted this so our new statement should be 'Action'
                if 'NotAction' in statement:
                    del statement['NotAction']

                # by putting this into a set, we lose order, which may be confusing to someone.
                statement['Action'] = sorted(list(statement_actions))

                # mark empty statements to be removed
                if len(statement['Action']) == 0:
                    empty_statements.append(idx)

        # do the actual removal of empty statements
        for idx in sorted(empty_statements, reverse=True):
            del policy['Statement'][idx]

        # mark empty policies to be removed
        if len(policy['Statement']) == 0:
            empty_policies.append(policy_name)

    # do the actual removal of empty policies.
    for policy_name in empty_policies:
        del role_policies[policy_name]

    return role_policies, empty_policies
Esempio n. 7
0
def _get_repoed_policy(role, repoable_permissions):
    """
    Iterate over role policies.
    Iterate over policy statements.
    Skip Deny statements.
    Remove any actions that are in repoable_permissions.
    Remove any statements that now have zero actions.
    Remove any policies that now have zero statements.
    return
    """
    # work with our own copy; don't mess with the CACHE copy.
    role_policies = dict(role['Policies'][-1]['Policy'])

    empty_policies = []
    for policy_name, policy in role_policies.items():
        empty_statements = []
        if type(policy['Statement']) is dict:
            policy['Statement'] = [policy['Statement']]
        for idx, statement in enumerate(policy['Statement']):
            if statement['Effect'].lower() == 'allow':
                statement_actions = get_actions_from_statement(statement)
                statement_actions = statement_actions.difference(
                    repoable_permissions)
                if 'NotAction' in statement:
                    del statement['NotAction']

                # by putting this into a set, we lose order, which may be confusing to someone.
                statement['Action'] = sorted(list(statement_actions))

                # mark empty statements to be removed
                if len(statement['Action']) == 0:
                    empty_statements.append(idx)

        # do the actual removal of empty statements
        for idx in sorted(empty_statements, reverse=True):
            del policy['Statement'][idx]

        # mark empty policies to be removed
        if len(policy['Statement']) == 0:
            empty_policies.append(policy_name)

    # do the actual removal of empty policies.
    for policy_name in empty_policies:
        del role_policies[policy_name]

    return role_policies, empty_policies
Esempio n. 8
0
def _get_role_permissions(role):
    permissions = set()
    for policy_name, policy in _get_current_policies(role).items():
        policy = expand_policy(policy=policy, expand_deny=False)
        for statement in policy.get('Statement'):
            if statement['Effect'].lower() == 'allow':
                permissions = permissions.union(
                    get_actions_from_statement(statement))

    for permission in permissions:
        if permission.startswith('tag:'):
            LOGGER.info('Role {} has {}'.format(role['RoleName'], permission))

    global WEIRD
    weird_permissions = permissions.difference(all_permissions)
    if weird_permissions:
        WEIRD = WEIRD.union(weird_permissions)

    return permissions
Esempio n. 9
0
def get_repoed_policy(
        policies: Dict[str, Any],
        repoable_permissions: Set[str]) -> Tuple[Dict[str, Any], List[str]]:
    """
    This function contains the logic to rewrite the policy to remove any repoable permissions. To do so we:
      - Iterate over role policies
      - Iterate over policy statements
      - Skip Deny statements
      - Remove any actions that are in repoable_permissions
      - Remove any statements that now have zero actions
      - Remove any policies that now have zero statements

    Args:
        policies (dict): All of the inline policies as a dict with name and policy contents
        repoable_permissions (set): A set of all of the repoable permissions for policies

    Returns:
        dict: The rewritten set of all inline policies
        list: Any policies that are now empty as a result of the rewrites
    """
    # work with our own copy; don't mess with the CACHE copy.
    role_policies = copy.deepcopy(policies)

    empty_policies = []
    for policy_name, policy in list(role_policies.items()):
        # list of indexes in the policy that are empty
        empty_statements = []

        if type(policy["Statement"]) is dict:
            policy["Statement"] = [policy["Statement"]]

        for idx, statement in enumerate(policy["Statement"]):
            if statement["Effect"].lower() == "allow":
                if "Sid" in statement and statement["Sid"].startswith(
                        STATEMENT_SKIP_SID):
                    continue

                statement_actions = get_actions_from_statement(statement)
                new_actions = {
                    action
                    for action in statement_actions
                    if action not in repoable_permissions
                    and action.split(":")[0] not in repoable_permissions
                }

                if statement_actions == new_actions:
                    # No permissions are being taken away; let's not modify this statement at all.
                    continue

                # get_actions_from_statement has already inverted this so our new statement should be 'Action'
                if "NotAction" in statement:
                    del statement["NotAction"]

                # by putting this into a set, we lose order, which may be confusing to someone.
                statement["Action"] = sorted(list(new_actions))

                # mark empty statements to be removed
                if len(statement["Action"]) == 0:
                    empty_statements.append(idx)

        # do the actual removal of empty statements
        for idx in sorted(empty_statements, reverse=True):
            del policy["Statement"][idx]

        # mark empty policies to be removed
        if len(policy["Statement"]) == 0:
            empty_policies.append(policy_name)

    # do the actual removal of empty policies.
    for policy_name in empty_policies:
        del role_policies[policy_name]

    return role_policies, empty_policies