From 6366835445b6077b867956db940e7a348ea2659e Mon Sep 17 00:00:00 2001 From: svalouch Date: Fri, 6 Mar 2020 17:51:05 +0100 Subject: [PATCH] Rework PE Helper documentation --- README.rst | 2 +- docs/pe_helper.rst | 111 +++++++++++++++++++++++++++++++++++++++++++ docs/security.rst | 95 +----------------------------------- src/simplezfs/zfs.py | 2 +- 4 files changed, 115 insertions(+), 95 deletions(-) diff --git a/README.rst b/README.rst index cc566ca..5ecd9c4 100644 --- a/README.rst +++ b/README.rst @@ -34,7 +34,7 @@ The table gives a rough overview over features and their implementation state. F | | +-----------------+-----+--------+-----------+ | | | Check existance | Yes | No | | | | +-----------------+-----+--------+-----------+ -| | | Create Fileset | No | No | No | +| | | Create Fileset | Yes | No | Yes | | | +-----------------+-----+--------+-----------+ | | | Create Volume | No | No | | | | +-----------------+-----+--------+-----------+ diff --git a/docs/pe_helper.rst b/docs/pe_helper.rst index 5407586..ad75841 100644 --- a/docs/pe_helper.rst +++ b/docs/pe_helper.rst @@ -1,3 +1,5 @@ +.. _privilege_escalation_helper: + ########################### Privilege Escalation Helper ########################### @@ -23,3 +25,112 @@ There are two implementations of PE Helpers provided: 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) | ++-------+------------------------------------------------------------------------+ + diff --git a/docs/security.rst b/docs/security.rst index 2469fac..f027bcd 100644 --- a/docs/security.rst +++ b/docs/security.rst @@ -33,97 +33,6 @@ Elevated privileges are required for the following tasks: * set or change the ``mountpoint`` property, which results in changing the mountpoint * ZPool ``import`` or ``export`` -Whether the helper is installed **setuid root** or uses **sudo** internally or any other way is up to the user. An -example helper script is provided that will allow creating and moving filesets in a subtree of the ZFS hierarchy and -local filesystem hierarchy. +Whether the helper is installed **setuid root** or uses **sudo** internally or any other way is up to the user. Head +over to :ref:`privilege_escalation_helper` for more info. -.. note:: - - The helper is provided as an example, use at your own risk. - -PE Helper protocol -****************** -The PE helper will be called with different sets of parameters, depending on the action to perform. Its exit code -communicates the basic problem or success and output is captured and fed to the logger. - -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) | -+-------+------------------------------------------------------------------------+ - -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``. diff --git a/src/simplezfs/zfs.py b/src/simplezfs/zfs.py index 11dd8ff..b4a3960 100644 --- a/src/simplezfs/zfs.py +++ b/src/simplezfs/zfs.py @@ -443,7 +443,7 @@ class ZFS: Please read the note in :func:`~simplezfs.ZFS.create_filesystem` for permission handling for filesystems. Generally, if the user does not have permission to set certain properties, the dataset may or may not have been created but is missing the properties. It is up to the user of the library to clean up after - catching a ``PermissionError`. + catching a :class:`+simplezfs.exceptions.PermissionError`. :param name: Name of the new volume (complete path in the ZFS hierarchy). :param size: The size (in `bytes`) for the new volume.