[neutron][nova][large scale SIG] Rootwrap daemon and privsep

Thierry Carrez thierry at openstack.org
Fri Nov 29 17:17:46 UTC 2019

Arnaud Morin wrote:
> [...] I'd like to understand the difference with privsep daemon.
> Is privsep a new daemon which is supposed to replace the rootwrap one?
> Is privsep being launch after rootwrap?
> IS privsep enabled by default, so I should not care about rootwrap at
> all?

I can help with that, since I originally created rootwrap.

Rootwrap is a privilege escalation control mechanism. It serves as a way 
to filter what the service user on the machine can execute as root via 
sudo. The idea is that sudoers files do not provide enough granularity, 
so instead of trying to describe what is allowed and what is not in 
sudoers file, we basically allow calling "sudo rootwrap command" and let 
rootwrap figure it out. Rootwrap reads a number of (root-owned) 
configuration files and decides to allow calling the command or not.

There are two issues with this mechanism. The first is that the 
performance is not great, as first you run a python executable 
(rootwrap), which in turn spawns another process if the command is 
allowed. If you do that for hundreds of "ip" calls as you set up 
networking in neutron, this can add up pretty fast.

The second issue is that rootwrap is only as secure as its 
configuration. If for example you configure rootwrap to allow the 'nova' 
user to run the "chmod" command, well that's basically the same as 
allowing it run anything as root. You have to use advanced filters to 
further refine what it can actually do based on command parameter 
analysis, and there is only so much you can control that way.

Rootwrap-daemon is a way to partially help with the first issue. Rather 
than calling a new rootwrap Python process every time a command needs to 
be called, you maintain a long-running rootwrap process that will 
process all requests. It significantly improves performance, but it adds 
inter-process communication complexity (never great in a security 
system). And it does nothing to address the second issue.

Privsep is the "right" way of addressing both issues. Rather than having 
the code try to call shell commands as root, privsep allows the code to 
call Python functions as root. This solves the performance issue, as you 
don't have the overhead of a separate Python process + shell process 
every time you want to change the ownership of a file, you can just call 
a Python function that will call os.chown() and get ear to syscall 
efficiency. It also solves the granularity issue, by allowing to call a 
function that will only do what you want to do, rather than have to find 
a way to filter parameters so that the command you call cannot be abused 
to do other things.

The main issue with privsep is that it requires changing the code. You 
have to set it up in every project (it's now done for most), but then 
every place the service calls utils.execute(command, run_as_root=True) 
needs to be changed to call a privileged Python function instead.

The second issue with privsep is that it still needs root to start. The 
way this is usually done is by using rootwrap itself to bootstrap 
privsep... which can be confusing. There are obviously other ways to 
start the process as root, but since most of those services still make 
use of rootwrap anyway, that is what continues to be used for the 
initial bootstrapping.

Ideally services would be completely transitioned to privsep, and we 
would discontinue rootwrap.

Hoping this helps,

Thierry Carrez (ttx)

More information about the openstack-discuss mailing list