You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
6.5 KiB
ReStructuredText

.. _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 <size>
<dataset>``. 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) |
+-------+------------------------------------------------------------------------+