openstack root-wrap
https://wiki.openstack.org/wiki/Rootwrap一.nova-rootwrap的作用
部署玩过openstack的都应该知道,它会生成一个nova用户来管理所有服务.nova身份在linux中属于普通用户级别,避免了一些需要root身份运行的操作,提高linux系统的安全性.
但是openstack在实际过程中会调用很多外部命令,例如就network服务而言就有:`ip`,`ovs-vsctl`,`iptables`,`dnsmasq`,`brctl`等等,这些命令在linux中都是需要以root身份来运行的,如果是普通用户通常的做法是在命令前加`sudo`切换到root身份再执行这些命令,但是这个方法在执行命令的时候需要输入密码确认操作,为了避免输入密码,我们需要配置一下sudo.
建议的方法是在/etc/sudoers.d/目录下新建一个文件,例如:
# pwd/etc/sudoers.d # echo 'zhengtianbao ALL = (root) NOPASSWD: ALL' > stack_sh# cat stack_sh zhengtianbao ALL = (root) NOPASSWD: ALL 这样当我们切换到’zhengtianbao’这个用户的时候,只要在想执行的命令前加’sudo’,不需要输入密码就能以root身份运行.
# su zhengtianbao$ lsls: cannot open directory .: Permission denied$ sudo lsstack_sh 关于sudoers的配置文件如何定义,这里简单介绍下:
通用格式:
user host run_as command
user:一位或几位用户,在/etc/group中可以用一个%代替它,组对象的名称一定要用百分号%开头.
host:一个或几个主机名.
run_as:作为哪个用户运行,常见选项是root和ALL.
command:想让用户或组运行的一个或几个根级别命令.
例如:
hans ALL=(root) useradd,userdel
授权hans用户在所有计算机上以root身份运行useradd,userdel命令.
%smith ALL=(ALL) NOPASSWD:useradd,userdel
授权smith组全部成员在所有计算机上以所有用户的身份运行useradd,userdel命令;且运行时不必输入密码.
一点点疑问:能否控制命令的参数呢?接下来做个测试:
# echo 'zhengtianbao ALL = (root) NOPASSWD: /bin/ls -l, /bin/ls -a' > stack_sh# su zhengtianbao$ ls -als: cannot open directory .: Permission denied$ sudo ls -a...stack_sh $ sudo ls -ltotal 8 -rw-r--r-- 1 root root59 Jan 26 14:43 stack_sh$ sudo ls -a -l password for zhengtianbao: 可见能够控制的命令参数还是很严格的.
放在openstack中这也是可行的,但是随着项目的增大,单纯的修改sudoers影响了openstack的可维护性,因此引入了root warpper来管理命令权限相关的内容.
二.nova-rootwrap工作原理
如果是根据devstack来安装openstack的话,查看devstack中的stack.sh里面有关于root权限的内容:
# root Access # ----------- # OpenStack is designed to be run as a non-root user; Horizon will fail to run# as **root** since Apache will not serve content from **root** user).# ``stack.sh`` must not be run as **root**.It aborts and suggests one course of# action to create a suitable user account.if[[ $EUID -eq0 ]];then echo"You are running this script as root." echo"Cut it out." echo"Really." echo"If you need an account to run DevStack, do this (as root, heh) to create $STACK_USER:" echo"$TOP_DIR/tools/create-stack-user.sh" exit1fi # We're not **root**, make sure ``sudo`` is availableis_package_installedsudo|| install_packagesudo 好,它这里表示需要先通过脚本tools/create-stack-user.sh来创建一个用户,再通过那个用户来执行,看脚本内容:
# Needed to get ``ENABLED_SERVICES``source $TOP_DIR/stackrc # Give the non-root user the ability to run as **root** via ``sudo``is_package_installedsudo|| install_packagesudo if! getent group $STACK_USER >/dev/null;then echo"Creating a group called $STACK_USER" groupadd $STACK_USER fi if! getentpasswd$STACK_USER >/dev/null;then echo"Creating a user called $STACK_USER" useradd-g $STACK_USER -s/bin/bash-d $DEST -m $STACK_USERfi echo"Giving stack user passwordless sudo privileges"# UEC images ``/etc/sudoers`` doesnot have a ``#includedir``, add onegrep -q "^#includedir.*/etc/sudoers.d" /etc/sudoers || echo"#includedir /etc/sudoers.d">> /etc/sudoers( umask226 &&echo "$STACK_USER ALL=(ALL) NOPASSWD:ALL"\ >/etc/sudoers.d/50_stack_sh) $STACK_USER的值在stackrc文件中定义,当前环境是root身份时则为’stack’:
# Determine stack userif [[ $EUID -eq 0 ]];then STACK_USER=stackelse STACK_USER=$(whoami)fi ok,这里发现它在/etc/sudoers.d/目录下生成了一个50_stack_sh的文件,里面的内容是:
stack ALL=(ALL) NOPASSWD:ALL
显然它创建的stack用户现在可以在使用`sudo`执行任何命令都能省略输入密码的过程了.
接下来继续看nova的安装过程,在devstack/lib/目录下的nova脚本中有configure_nova()的方法,它会在stack.sh中被调用到,正如名字所示,它用来设置nova的config文件,创建一些数据等工作:
# configure_nova() - Set config files, create data dirs, etcfunction configure_nova() { # Put config files in ``/etc/nova`` for everyone to find if [[ ! -d $NOVA_CONF_DIR ]];then sudomkdir-p $NOVA_CONF_DIR fi sudochown$STACK_USER $NOVA_CONF_DIR cp-p $NOVA_DIR/etc/nova/policy.json $NOVA_CONF_DIR configure_nova_rootwrap ... 注意里面的configure_nova_rootwrap,查看该方法:
# configure_nova_rootwrap() - configure Nova's rootwrapfunction configure_nova_rootwrap() { # Deploy new rootwrap filters files (owned by root). # Wipe any existing rootwrap.d files first if [[ -d $NOVA_CONF_DIR/rootwrap.d ]];then sudorm-rf $NOVA_CONF_DIR/rootwrap.d fi # Deploy filters to /etc/nova/rootwrap.d sudo mkdir-m 755 $NOVA_CONF_DIR/rootwrap.d sudocp$NOVA_DIR/etc/nova/rootwrap.d/*.filters $NOVA_CONF_DIR/rootwrap.d sudochown-R root:root $NOVA_CONF_DIR/rootwrap.d sudochmod644 $NOVA_CONF_DIR/rootwrap.d/* # Set up rootwrap.conf, pointing to /etc/nova/rootwrap.d sudo cp $NOVA_DIR/etc/nova/rootwrap.conf $NOVA_CONF_DIR/ sudosed-e "s:^filters_path=.*$:filters_path=$NOVA_CONF_DIR/rootwrap.d:"-i $NOVA_CONF_DIR/rootwrap.conf sudochownroot:root $NOVA_CONF_DIR/rootwrap.conf sudochmod0644 $NOVA_CONF_DIR/rootwrap.conf # Specify rootwrap.conf as first parameter to nova-rootwrap ROOTWRAP_SUDOER_CMD="$NOVA_ROOTWRAP $NOVA_CONF_DIR/rootwrap.conf *" # Set up the rootwrap sudoers for nova TEMPFILE=`mktemp` echo"$STACK_USER ALL=(root) NOPASSWD: $ROOTWRAP_SUDOER_CMD">$TEMPFILE chmod0440 $TEMPFILE sudochownroot:root $TEMPFILE sudomv$TEMPFILE /etc/sudoers.d/nova-rootwrap} 显然,它在/etc/sudoers.d/目录下创建了nova-rootwrap的文件,里面的内容可能是:
nova ALL = (root) NOPASSWD: /usr/bin/nova-rootwrap /etc/nova/rootwrap.conf *
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 …`.
/usr/bin/nova-rootwrap是一个可执行的脚本文件,/etc/nova/rootwrap.conf则是rootwrap相关的配置,里面定义了filters-path所在路径,以及缺省的可执行命令所在路径,具体的过滤逻辑如下:
1)获取要执行的命令,如:ip
2)通过filters-path加载配置文件中定义的可以执行的命令列表
3)判断命令是否在可执行命令列表中
4)若在则通过python的subprocess模块执行Popen方法;不在则给出错误信息,退出.
这些都可以在nova的bin/nova-rootwrap文件中查看.
三.nova中执行外部命令过程分析
所有的nova代码在执行外部命令的时候都会用到execute函数,这个函数定义在nova顶层目录下的utils.py模块下.
例如:
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 defexecute(*cmd,**kwargs): """Convenience wrapper around oslo's execute() method.""" if'run_as_root'inkwargs andnot 'root_helper'in kwargs: kwargs['root_helper']=_get_root_helper() returnprocessutils.execute(*cmd,**kwargs) 然后丢给processutils中的execute,查看代码:
def execute(*cmd,**kwargs): ... ifrun_as_rootandhasattr(os,'geteuid') andos.geteuid() !=0: ifnotroot_helper: raiseNoRootWrapSpecified( message=_('Command requested root, butdid not ' 'specify a root helper.')) cmd=shlex.split(root_helper)+list(cmd) cmd=map(str, cmd) whileattempts >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/filters.py中,里面还定义了其他的filter(RegExp,Path,Kill,ReadFile,Ip,Env,Chaining,IpNetnsExec).
更加详细的内容请查看nova/rootwarp目录下的filters.py与wrapper.py.
页:
[1]