OpenStack oslo.rootwrap
普通用户执行 root
权限的 linux
命令实现原理。
目标
实现普通用户执行 root
命令。
实现方式
通用配置 /etc/sudoers.d/nova
允许 nova
用户作为 root
运行 nova-rootwrap
,通过 /etc/nova/rootwrap.d/*.filters
过滤器限定命令范围。Available Filter classes
$ cat /etc/sudoers.d/nova
Defaults:nova !requiretty
nova ALL = (root) NOPASSWD: /usr/bin/nova-rootwrap /etc/nova/rootwrap.conf *
以nova
身份运行命令 sudo /usr/bin/nova-rootwrap /etc/nova/rootwrap.conf *
时,是不需要输入密码的,其中的 *
指的是任意字符串,例如:ip route show ...
示例
from nova import utils
utils.execute('chmod', '777', tmpdir, run_as_root=True)
execute
函数首先根据 run_as_root
参数进行如下处理:
def _get_root_helper():
return 'sudo nova-rootwrap %s' % CONF.rootwrap_config
def execute(*cmd, **kwargs):
"""Convenience wrapper around oslo's execute() method."""
if 'run_as_root' in kwargs and not 'root_helper' in kwargs:
kwargs['root_helper'] = _get_root_helper()
return processutils.execute(*cmd, **kwargs)
然后丢给 processutils
中的 execute
,查看代码:
def execute(*cmd, **kwargs):
...
if run_as_root and hasattr(os, 'geteuid') and os.geteuid() != 0:
if not root_helper:
raise NoRootWrapSpecified(
message=_('Command requested root, but did not '
'specify a root helper.'))
cmd = shlex.split(root_helper) + list(cmd)
cmd = map(str, cmd)
while attempts > 0:
...
obj = subprocess.Popen(cmd,
stdin=_PIPE,
stdout=_PIPE,
stderr=_PIPE,
close_fds=close_fds,
preexec_fn=preexec_fn,
shell=shell)
...
最终执行的cmd命令:
sudo /usr/bin/nova-rootwrap /etc/nova/rootwrap.conf chmod 777 tmpdir
这里chmod
这个命令在 rootwrap.d
目录下的 filters
文件中可以找到对应的配置:
chmod: CommandFilter, chmod, root
CommandFilter
的定义是在 oslo.rootwrap
的 oslo_rootwrap/filters.py
中,里面还定义了其他的 filter
,如:RegExpFilter、PathFilter、KillFilter、ReadFileFilter、EnvFilter、ChainingFilter、IpNetnsExecFilter、ChainingRegExpFilter。通过 oslo_rootwrap/wrapper.py:start_subprocess
调用命令。