.. _privilege_escalation_helper: ########################### Privilege Escalation Helper ########################### The Privilege Escalation Helper (**PE Helper**) mechanism works around the problem that only `root` is allowed to manipulate the global namespace on Linux hosts, which means that only `root` can mount and unmount filesystems / filesets. In normal operation, users can be granted permission to do almost anything with a ZFS, except for mounting. Thus, elevated privileges are required for these actions, which in particular revolves around: * Creating a fileset with the ``mountpoint`` property set * Mounting or unmounting a fileset * Destroying a mounted fileset While the PE Helper may be useful in other areas, such as acting as a ``sudo(8)`` wrapper, its use is limited to the bare minimum. All other actions can be performed by using ``zfs allow`` to allow low-privilege-users to perform them. There are two implementations of PE Helpers provided: * :class:`~simplezfs.pe_helper.ExternalPEHelper` which runs a user-specified script or program to perform the actions, one is provided as an example in the `scripts` folder. This is the most flexible and possibly the most dangerous way to handle things. * :class:`~simplezfs.pe_helper.SudoPEHelper` simply runs the commands through ``sudo(8)``, so the user needs to set up their ``/etc/sudoers`` accordingly. Additonal implementations need only to inherit from :class:`~simplezfs.pe_helper.PEHelperBase`. When to use *********** The helper is generally only required on Linux, where, according to the ``zfs(8)`` manpage on ``zfs allow``, the ``mount(8)`` "command restricts modifications of the global namespace to the root user". The permissions that require ``root`` are: * ``mount`` * ``unmount`` * ``canmount`` * ``rename`` * ``share`` As some commands manipulate the namespace, the following actions require root permission: * ``clone`` * ``create`` (:func:`~simplezfs.ZFS.create_fileset` because it mounts it right away) * ``destroy`` (:func:`~simplezfs.ZFS.destroy_dataset`) * ``mount`` * ``promote`` * ``receive`` * ``rename`` * ``rollback`` * ``share`` * ``snapshot`` (:func:`~simplezfs.ZFS.create_snapshot`) Additionally, changing the ``mountpoint`` property on filesets (:func:`~simplezfs.ZFS.set_mountpoint`) When not to use *************** The privilege escalation helper implements only the absolute minimum that is required. For everything else, the user is expected to use ``zfs allow`` to delegate the permissions to the user. For example, it does not implement volume creation, only filesets are handled. Delegation (``zfs allow``) ************************** Using ``zfs allow``, a lot of the required permissions can be delegated to the user. For example, to create volumes, one needs the following permissions: * ``create`` * ``volsize`` * ``refreservation`` ``create`` is the command, and ``volsize`` and ``refreservation`` are properties set by ``zfs create -V ``. Some more may be required with other options (such as ``volblocksize`` etc.) Since it does not mount the volume (as opposed to a fileset), the privilege escalation helper is not required and the permissions are expected to be delegated to the user running the program using ``zfs allow``. Implementations *************** This section is about the PE Helper implementation provided, from a user point of view. SudoPEHelper ============ The helper probably used most uses standard ``sudo(0)`` to escalate privileges. It basically prefixes the commands to run with ``sudo -n``. It is the most straight-forward way to go, and relies on the ``sudoers(5)`` file to allow passwordless sudo for the ZFS commands. Entering a password is not supported. As the only account that is allowed to mount, the user used is not configurable. Example ------- .. code-block:: python from simplezfs.zfs import get_zfs from simplezfs.pe_helper import SudoPEHelper z = get_zfs(pe_helper=SudoPEHelper(), use_pe_helper=True) z.create_fileset('rpool/test/test', mountpoint='/tmp/test') ExternalPEHelper ================ This helper uses an external script that carries out the work. A script is provided as an example (`scripts` subfolder). Calling convention ------------------ The `first` parameter denotes the ``action``, followed by one or two parameters: * ``create`` is used when creating a fileset. It receives the ``fileset`` name, and the ``mountpoint``. The PE helper should then issue the equivalent to ``zfs create -o mountpoint=$mountpoint $fileset``. * ``set_mountpoint`` sets or changes the mountpoint property of filesets, which usually results in remounting to the new location. It receives the ``fileset`` name and the new ``mountpoint``. * ``import``/``export`` imports or exports a pool. It takes a ``pool`` name as parameter. Reporting --------- If all went well, the helper shall return ``0`` as exit code. Otherwise, the exit code denotes the nature of the problem. Text output to stdout/stderr is captured and logged as info (if the exit code is ``0``) or error (otherwise). The logger is either called ``simplezfs.zfs.pe_helper`` or ``simplezfs.zpool.pe_helper``, depending on the usage. +-------+------------------------------------------------------------------------+ | Exit | Meaning | +-------+------------------------------------------------------------------------+ | ``0`` | Everything went well | +-------+------------------------------------------------------------------------+ | ``1`` | Parameter or general error, such as missing utilities | +-------+------------------------------------------------------------------------+ | ``2`` | The parent directory does not exist or is not a directory | +-------+------------------------------------------------------------------------+ | ``3`` | The parent dataset does not exist | +-------+------------------------------------------------------------------------+ | ``4`` | The target fileset is not in the hierarchy of the parent dataset | +-------+------------------------------------------------------------------------+ | ``5`` | The mountpoint is not inside the parent directory or otherwise invalid | +-------+------------------------------------------------------------------------+ | ``6`` | Calling the zfs utilities failed (when carrying out the command) | +-------+------------------------------------------------------------------------+