예제 #1
0
def update_role_data(dynamo_table,
                     account_number,
                     role,
                     current_policy,
                     source='Scan',
                     add_no_repo=True):
    """
    Compare the current version of a policy for a role and what has been previously stored in Dynamo.
      - If current and new policy versions are different store the new version in Dynamo. Add any newly added
          permissions to temporary permission blacklist. Purge any old entries from permission blacklist.
      - Refresh the updated time on the role policy
      - If the role is completely new, store the first version in Dynamo
      - Updates the role with full history of policies, including current version

    Args:
        dynamo_table
        account_number
        role (Role): current role being updated
        current_policy (dict): representation of the current policy version
        source: Default 'Scan' but could be Repo, Rollback, etc

    Returns:
        None
    """

    # policy_entry: source, discovered, policy
    stored_role = get_role_data(dynamo_table,
                                role.role_id,
                                fields=['OptOut', 'Policies'])
    if not stored_role:
        role_dict = store_initial_role_data(dynamo_table, role.arn,
                                            role.create_date, role.role_id,
                                            role.role_name, account_number,
                                            current_policy)
        role.set_attributes(role_dict)
        LOGGER.info('Added new role ({}): {}'.format(role.role_id, role.arn))
    else:
        # is the policy list the same as the last we had?
        old_policy = stored_role['Policies'][-1]['Policy']
        if current_policy != old_policy:
            add_new_policy_version(dynamo_table, role, current_policy, source)
            LOGGER.info(
                '{} has different inline policies than last time, adding to role store'
                .format(role.arn))

            newly_added_permissions = find_newly_added_permissions(
                old_policy, current_policy)
        else:
            newly_added_permissions = set()

        if add_no_repo:
            update_no_repo_permissions(dynamo_table, role,
                                       newly_added_permissions)
        update_opt_out(dynamo_table, role)
        set_role_data(dynamo_table, role.role_id,
                      {'Refreshed': datetime.datetime.utcnow().isoformat()})

        role.policies = get_role_data(dynamo_table,
                                      role.role_id,
                                      fields=['Policies'])['Policies']
예제 #2
0
def update_role_data(dynamo_table,
                     account_number,
                     role,
                     current_policy,
                     current_managed_policy,
                     source="Scan",
                     add_no_repo=True,
                     include_managed_policies=True):
    """
    Compare the current version of a policy for a role and what has been previously stored in Dynamo.
      - If current and new policy versions are different store the new version in Dynamo. Add any newly added
          permissions to temporary permission blocklist. Purge any old entries from permission blocklist.
      - Refresh the updated time on the role policy
      - If the role is completely new, store the first version in Dynamo
      - Updates the role with full history of policies, including current version

    Args:
        dynamo_table
        account_number
        role (Role): current role being updated
        current_policy (dict): representation of the current policy version
        current_managed_policy (dict): representation of the current managed policy versions
        source: Default 'Scan' but could be Repo, Rollback, etc
        add_no_repo (bool)

    Returns:
        None
    """

    # policy_entry: source, discovered, policy
    stored_role = get_role_data(
        dynamo_table,
        role.role_id,
        fields=["OptOut", "Policies", "ManagedPolicies", "Tags"])
    if not stored_role:
        role_dict = store_initial_role_data(
            dynamo_table,
            role.arn,
            role.create_date,
            role.role_id,
            role.role_name,
            account_number,
            current_policy,
            current_managed_policy,
            role.tags,
        )
        role_updates = Role.parse_obj(role_dict)
        update_dict = role_updates.dict(exclude_unset=True)
        role = role.copy(update=update_dict)
        LOGGER.info("Added new role ({}): {}".format(role.role_id, role.arn))
        return role
    else:
        # is the policy list the same as the last we had?
        old_policy = stored_role["Policies"][-1]["Policy"]
        if current_policy != old_policy:
            add_new_policy_version(dynamo_table, role, current_policy, source)
            LOGGER.info(
                "{} has different inline policies than last time, adding to role store"
                .format(role.arn))
            newly_added_permissions = find_newly_added_permissions(
                old_policy, current_policy)

        else:
            newly_added_permissions = set()

        # TODO Make this part of set_role_data instead to allow updating existing dynamo tables
        # TODO this code will not work with existing dynamo tables - because old roles won't have ManagedPolicies
        old_managed_policy = stored_role["ManagedPolicies"][-1]["Policy"]
        if current_managed_policy != old_managed_policy:
            add_new_managed_policy_version(dynamo_table, role,
                                           current_managed_policy, source)
            LOGGER.info(
                "{} has different managed policies than last time, adding to role store"
                .format(role.arn))

            newly_added_managed_permissions = find_newly_added_permissions(
                old_managed_policy, current_managed_policy)

        else:
            newly_added_managed_permissions = set()

        # update tags if needed
        if role.tags != stored_role.get("Tags", []):
            set_role_data(dynamo_table, role.role_id, {"Tags": role.tags})

        if add_no_repo:
            update_no_repo_permissions(dynamo_table, role,
                                       newly_added_permissions)
            if include_managed_policies:
                update_no_repo_permissions(dynamo_table, role,
                                           newly_added_managed_permissions)
        update_opt_out(dynamo_table, role)
        set_role_data(
            dynamo_table,
            role.role_id,
            {"Refreshed": datetime.datetime.utcnow().isoformat()},
        )

        # Update all data from Dynamo except CreateDate (it's in the wrong format) and DQ_by (we're going to recalc)
        current_role_data = get_role_data(dynamo_table, role.role_id)
        current_role_data.pop("CreateDate", None)
        current_role_data.pop("DisqualifiedBy", None)

        # Create an updated Role model to be returned to the caller
        role_updates = Role.parse_obj(current_role_data)
        update_dict = role_updates.dict(exclude_unset=True)
        role = role.copy(update=update_dict)

        return role