Sudo Policies and Privileges
============================

Exosphere and its provider modules try, as much as possible, to avoid requiring elevated
privileges at all. Unfortunately, on some platforms, some operations that we rely on
do require them.

This section describes how to configure the Sudo Policy for Exosphere as well
as optionally grant the required privileges on the remote hosts.

.. admonition:: Note

    These instructions below are entirely optional, and you can absolutely use
    Exosphere without ever setting up sudoers configuration or privileges.
    You will just be limited to the operations that do not require
    elevated privileges, which is the majority of them.

Enumerating Providers and their Privileges
------------------------------------------

The documentation for :doc:`providers` includes details, but you can query this via the
exosphere CLI and its ``sudo`` command. Here is an example below:

.. code-block:: console

    $ exosphere sudo providers
                                    Providers Requirements
    ┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
    ┃ Provider ┃ Platform                       ┃ Sync Repositories ┃ Refresh Updates ┃
    ┡━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩
    │ Apt      │ Debian/Ubuntu Derivatives      │ Requires Sudo     │ No Privileges   │
    │ Pkg      │ FreeBSD                        │ Requires Sudo     │ No Privileges   │
    │ PkgAdd   │ OpenBSD                        │ No Privileges     │ No Privileges   │
    │ Dnf      │ Fedora/RHEL/CentOS Derivatives │ No Privileges     │ No Privileges   │
    │ Yum      │ RHEL/CentOS 7 and earlier      │ No Privileges     │ No Privileges   │
    └──────────┴────────────────────────────────┴───────────────────┴─────────────────┘

For instance, we can see here that the ``Apt`` and ``Pkg`` providers require sudo privileges
to sync repositories, but do not require any privileges to refresh updates.

.. note::
   The table above shows the privilege requirements for each operation type:

   * **Sync Repositories**: Updating package repository metadata (e.g., ``apt-get update``)
   * **Refresh Updates**: Checking for available package updates

Configuring Sudo Policies
-------------------------

There are currently two valid settings for the Sudo Policy options:

* ``skip``: Do not use sudo at all, skip operations that require it and emit a warning in logs
* ``nopasswd``: Assume sudoers configuration allows running the provider commands without a password

The default Sudo Policy for exosphere is `skip`, :ref:`configured globally <default_sudo_policy_option>`.
This means that Exosphere will not attempt to use sudo at all when running provider commands.

This can also be configured per system, by setting the :ref:`sudo policy option <hosts_sudo_policy_option>`
at the host level.

If you want to be able to use Exosphere to run operations that require sudo privileges, you will
need to configure sudoers on the remote host(s) where this applies to allow them to be run without
a password.

.. attention::

    This can potentially expose your system to security risks if not configured properly.
    See the section below for details on how to configure this safely.

.. _generating-a-sudoers-configuration:

Generating a Sudoers configuration
----------------------------------

You can manually configure sudoers with ``NOPASSWD:`` as you wish, so long as it allows
the commands specified in the :doc:`providers` documentation to run.

However, since this can be a combination of tedious, risky and error-prone,
Exosphere provides a helper command that will generate a sudoers snippet for you,
for any host, or specific provider, while also allowing you to specify a username.

To generate a sudoers configuration snippet for the ``Apt`` provider, for instance,
with the username ``bigadmin``, you can run the following command:

.. code-block:: console

    $ exosphere sudo generate --provider apt --user bigadmin
    # Generated for Debian/Ubuntu Derivatives
    Cmnd_Alias EXOSPHERE_CMDS = /usr/bin/apt-get update
    bigadmin ALL=(root) NOPASSWD: EXOSPHERE_CMDS

You can then take this output and drop it in a file on the remote host, such as
``/etc/sudoers.d/zz-exosphere`` (or, if on a FreeBSD System,
``/usr/local/etc/sudoers.d/zz-exosphere``) and then switch the Sudo Policy to
``nopasswd`` for that host.

.. admonition:: On usernames

    The username parameter is optional. If you do not specify it, the command will
    try to use, in this order:

    1. The username configured for the host, if any (when using ``--host``)
    2. The username configured in the global configuration, if any
    3. The current local username running the exosphere command

You can also use the ``--host`` option to automatically detect the provider
for a host and generate the appropriate sudoers snippet for it.

For more details, see ``exosphere sudo generate --help``.

Security Considerations
^^^^^^^^^^^^^^^^^^^^^^^

The generated sudoers configuration is designed to be as secure as possible:

* **Specific commands only**: Only the exact commands needed by the provider are allowed
* **Absolute paths**: Commands use full absolute paths (e.g., ``/usr/bin/apt-get``)
* **Root user only**: Commands are restricted to run as ``root`` (not ``ALL``)
* **No password required**: Uses ``NOPASSWD:`` to avoid credential storage/prompting
* **Command aliases**: Uses ``Cmnd_Alias`` for better maintainability

This approach is significantly more secure than granting broad sudo access, as it:

* Limits the attack surface to specific commands that are known in advance
* Prevents privilege escalation beyond the intended operations
* Avoids the security risks of password-based authentication

Alternatives
^^^^^^^^^^^^

If your relevant providers only require sudo privileges for repository synchronization,
and you prefer not to use the sudoers configuration, you can still
configure your remote systems to sync those repositories on a schedule.
You will just not be able to use Exosphere to do it on-demand, but the
repository contents should always be reasonably up to date.

On Debian/Ubuntu systems, consider these options:

* The `unattended-upgrades`_ package, which can be configured to automatically
  run ``apt-get update`` and optionally ``apt-get upgrade`` on a schedule
* The ``apt-config-auto-update`` package for simpler automatic update configuration
* Custom cron jobs with ``apt-get update`` if you prefer manual control

On FreeBSD, you can set up a cron job or periodic task to run
``/usr/sbin/pkg update`` regularly.

For other distributions, similar automated package management tools are available.

How can I check what the effective Sudo Policy is for a given host?
-------------------------------------------------------------------

You can use the ``sudo check`` helper command.

As an example, to check the effective Sudo Policy for a host named ``bigserver``:

.. code-block:: console

    $ exosphere sudo check bigserver
    Sudo Policy for bigserver

     Global Policy:          skip
     Host Policy:            nopasswd (local)
     Package Manager:        apt

     Can Sync Repositories:  Yes
     Can Refresh Updates:    Yes

This will tell you what the effective Sudo Policy is for that host, as well as
where that is configured. For instance, in the example above, you can see the
global policy is ``skip``, but the host policy has been set to ``nopasswd``
locally, in the inventory host options.

The global Sudo Policy can also be displayed via:

.. code-block:: console

    $ exosphere sudo policy
    Global SudoPolicy: skip

.. _unattended-upgrades: https://wiki.debian.org/UnattendedUpgrades
