ahxcjxzxh 发表于 2015-10-10 14:20:49

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]
查看完整版本: openstack root-wrap