summaryrefslogtreecommitdiff
path: root/README.rst
diff options
context:
space:
mode:
authorThierry Carrez <thierry@openstack.org>2013-11-27 15:17:52 +0100
committerThierry Carrez <thierry@openstack.org>2013-11-27 15:26:52 +0100
commit7effec053445f52a520002ed9445980bf39d6bcd (patch)
treed950ba4c6716555b175b0c589f86a18d4dca2d52 /README.rst
parentfe258e097fbd1f6a1a06fb6ac31d4b338c6d6eca (diff)
downloadoslo-rootwrap-7effec053445f52a520002ed9445980bf39d6bcd.tar.gz
Add a complete README.rst
Document the use of oslo-rootwrap in README.rst, before cutting a first release. This obsoletes https://wiki.openstack.org/wiki/Rootwrap Change-Id: Ia7046e5a3c4b5ebdbc1a2d978cb6c6a9e4c69514
Diffstat (limited to 'README.rst')
-rw-r--r--README.rst271
1 files changed, 269 insertions, 2 deletions
diff --git a/README.rst b/README.rst
index caef8b0..39e2195 100644
--- a/README.rst
+++ b/README.rst
@@ -1,5 +1,272 @@
+-------------
Oslo Rootwrap
-=============
+-------------
-The Oslo Rootwrap allows fine filtering of shell commands to run as root
+The Oslo Rootwrap allows fine filtering of shell commands to run as `root`
from OpenStack services.
+
+Unlike other Oslo deliverables, it should **not** be used as a Python library,
+but called as a separate process through the `oslo-rootwrap` command:
+
+`sudo oslo-rootwrap ROOTWRAP_CONFIG COMMAND_LINE`
+
+How rootwrap works
+==================
+
+OpenStack services generally run under a specific, unprivileged user. However,
+sometimes they need to run a command as `root`. Instead of just calling
+`sudo make me a sandwich` and have a blanket `sudoers` permission to always
+escalate rights from their unprivileged users to `root`, those services can
+call `sudo oslo-rootwrap /etc/oslo/rootwrap.conf make me a sandwich`.
+
+A sudoers entry lets the unprivileged user run `oslo-rootwrap` as `root`.
+`oslo-rootwrap` looks for filter definition directories in its configuration
+file, and loads command filters from them. Then it checks if the command
+requested by the OpenStack service matches one of those filters, in which
+case it executes the command (as `root`). If no filter matches, it denies
+the request. This allows for complex filtering of allowed commands, as well
+as shipping filter definitions together with the OpenStack code that needs
+them.
+
+Security model
+==============
+
+The escalation path is fully controlled by the `root` user. A `sudoers` entry
+(owned by `root`) allows the unprivileged user to run (as `root`) a specific
+rootwrap executable, and only with a specific configuration file (which should
+be owned by `root`) as its first parameter.
+
+`oslo-rootwrap` imports the Python modules it needs from a cleaned (and
+system-default) `PYTHONPATH`. The configuration file points to root-owned
+filter definition directories, which contain root-owned filters definition
+files. This chain ensures that the unprivileged user itself is never in
+control of the configuration or modules used by the `oslo-rootwrap` executable.
+
+Installation
+============
+
+All nodes wishing to run `oslo-rootwrap` should contain a `sudoers` entry that
+lets the unprivileged user run `oslo-rootwrap` as `root`, pointing to the
+root-owned `rootwrap.conf` configuration file and allowing any parameter
+after that. For example, Nova nodes should have this line in their `sudoers`
+file, to allow the `nova` user to call `sudo oslo-rootwrap`:
+
+``nova ALL = (root) NOPASSWD: /usr/bin/oslo-rootwrap /etc/oslo/rootwrap.conf *``
+
+Then the node also should ship the filter definitions corresponding to its
+usage of `oslo-rootwrap`. You should not install any other filters file on
+that node, otherwise you would allow extra unneeded commands to be run as
+`root`.
+
+The filter file(s) corresponding to the node must be installed in one of the
+filters_path directories (preferably `/usr/share/oslo/rootwrap`). For example,
+on Nova compute nodes, you should only have
+`/usr/share/oslo/rootwrap/compute.filters` installed. The file should be owned
+and writeable only by the `root` user.
+
+Rootwrap configuration
+======================
+
+The `rootwrap.conf` file is used to influence how `oslo-rootwrap` works. Since
+it's in the trusted security path, it needs to be owned and writeable only by
+the `root` user. Its location is specified in the `sudoers` entry, and must be
+provided on `oslo-rootwrap` command line as its first argument.
+
+`rootwrap.conf` uses an *INI* file format with the following sections and
+parameters:
+
+[DEFAULT] section
+-----------------
+
+filters_path
+ Comma-separated list of directories containing filter definition files.
+ All directories listed must be owned and only writeable by `root`.
+ Example:
+ ``filters_path=/etc/oslo/rootwrap.d,/usr/share/oslo/rootwrap``
+
+exec_dirs
+ Comma-separated list of directories to search executables in, in case
+ filters do not explicitely specify a full path. If not specified, defaults
+ to the system `PATH` environment variable. All directories listed must be
+ owned and only writeable by `root`. Example:
+ ``exec_dirs=/sbin,/usr/sbin,/bin,/usr/bin``
+
+use_syslog
+ Enable logging to syslog. Default value is False. Example:
+ ``use_syslog=True``
+
+syslog_log_facility
+ Which syslog facility to use for syslog logging. Valid values include
+ `auth`, `authpriv`, `syslog`, `user0`, `user1`...
+ Default value is `syslog`. Example:
+ ``syslog_log_facility=syslog``
+
+syslog_log_level
+ Which messages to log. `INFO` means log all usage, `ERROR` means only log
+ unsuccessful attempts. Example:
+ ``syslog_log_level=ERROR``
+
+.filters files
+==============
+
+Filters definition files contain lists of filters that `oslo-rootwrap` will
+use to allow or deny a specific command. They are generally suffixed by
+`.filters`. Since they are in the trusted security path, they need to be
+owned and writeable only by the `root` user. Their location is specified
+in the `rootwrap.conf` file.
+
+It uses an *INI* file format with a `[Filters]` section and several lines,
+each with a unique parameter name (different for each filter you define):
+
+[Filters] section
+-----------------
+
+filter_name (different for each filter)
+ Comma-separated list containing first the Filter class to use, followed
+ by that Filter arguments (which vary depending on the Filter class
+ selected). Example:
+ ``kpartx: CommandFilter, /sbin/kpartx, root``
+
+
+Available filter classes
+========================
+
+CommandFilter
+-------------
+
+Basic filter that only checks the executable called. Parameters are:
+
+1. Executable allowed
+2. User to run the command under
+
+Example: allow to run kpartx as the root user, with any parameters:
+
+``kpartx: CommandFilter, kpartx, root``
+
+RegExpFilter
+------------
+
+Generic filter that checks the executable called, then uses a list of regular
+expressions to check all subsequent arguments. Parameters are:
+
+1. Executable allowed
+2. User to run the command under
+3. (and following) Regular expressions to use to match first (and subsequent)
+ command arguments
+
+Example: allow to run `/usr/sbin/tunctl`, but only with three parameters with
+the first two being -b and -t:
+
+``tunctl: /usr/sbin/tunctl, root, tunctl, -b, -t, .*``
+
+PathFilter
+----------
+
+Generic filter that lets you check that paths provided as parameters fall
+under a given directory. Parameters are:
+
+1. Executable allowed
+2. User to run the command under
+3. (and following) Command arguments.
+
+There are three types of command arguments: `pass` will accept any parameter
+value, a string will only accept the corresponding string as a parameter,
+except if the string starts with '/' in which case it will accept any path
+that resolves under the corresponding directory.
+
+Example: allow to chown to the 'nova' user any file under /var/lib/images:
+
+``chown: PathFilter, /bin/chown, root, nova, /var/lib/images``
+
+EnvFilter
+---------
+
+Filter allowing extra environment variables to be set by the calling code.
+Parameters are:
+
+1. `env`
+2. User to run the command under
+3. (and following) name of the environment variables that can be set,
+ suffixed by `=`
+4. Executable allowed
+
+Example: allow to run `CONFIG_FILE=foo NETWORK_ID=bar dnsmasq ...` as root:
+
+``dnsmasq: EnvFilter, env, root, CONFIG_FILE=, NETWORK_ID=, dnsmasq``
+
+ReadFileFilter
+--------------
+
+Specific filter that lets you read files as `root` using `cat`.
+Parameters are:
+
+1. Path to the file that you want to read as the `root` user.
+
+Example: allow to run `cat /etc/iscsi/initiatorname.iscsi` as `root`:
+
+``read_initiator: ReadFileFilter, /etc/iscsi/initiatorname.iscsi``
+
+KillFilter
+----------
+
+Kill-specific filter that checks the affected process and the signal sent
+before allowing the command. Parameters are:
+
+1. User to run `kill` under
+2. Only affect processes running that executable
+3. (and following) Signals you're allowed to send
+
+Example: allow to send `-9` or `-HUP` signals to `/usr/sbin/dnsmasq` processes:
+
+``kill_dnsmasq: KillFilter, root, /usr/sbin/dnsmasq, -9, -HUP``
+
+IpFilter
+--------
+
+ip-specific filter that allows to run any `ip` command, except for `ip netns`
+(in which case it only allows the list, add and delete subcommands).
+Parameters are:
+
+1. `ip`
+2. User to run `ip` under
+
+Example: allow to run any `ip` command except `ip netns exec` and
+`ip netns monitor`:
+
+``ip: IpFilter, ip, root``
+
+IpNetnsExecFilter
+-----------------
+
+ip-specific filter that allows to run any otherwise-allowed command under
+`ip netns exec`. The command specified to `ip netns exec` must match another
+filter for this filter to accept it. Parameters are:
+
+1. `ip`
+2. User to run `ip` under
+
+Example: allow to run `ip netns exec <namespace> <command>` as long as
+`<command>` matches another filter:
+
+``ip: IpNetnsExecFilter, ip, root``
+
+
+Calling oslo-rootwrap from OpenStack services
+=============================================
+
+The `oslo.processutils` library ships with a convenience `execute()` function
+that can be used to call shell commands as `root`, if you call it with the
+following parameters:
+
+``run_as_root=True``
+
+``root_helper='sudo oslo-rootwrap /etc/oslo/rootwrap.conf``
+
+NB: Some services ship with a `utils.execute()` convenience function that
+automatically sets `root_helper` based on the value of a `rootwrap_config`
+parameter, so only `run_as_root=True` needs to be set.
+
+If you want to call as `root` a previously-unauthorized command, you will also
+need to modify the filters (generally shipped in the source tree under
+`etc/rootwrap.d` so that the command you want to run as `root` will actually
+be allowed by `oslo-rootwrap`.