openstack root-wrap

来源:互联网 发布:淘宝需要注册公司吗 编辑:程序博客网 时间:2024/05/16 17:05

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/目录下新建一个文件,例如:

[root@localhost sudoers.d]# pwd
/etc/sudoers.d
[root@localhost sudoers.d]# echo 'zhengtianbao ALL = (root) NOPASSWD: ALL' > stack_sh
[root@localhost sudoers.d]# cat stack_sh 
zhengtianbao ALL = (root) NOPASSWD: ALL

这样当我们切换到’zhengtianbao’这个用户的时候,只要在想执行的命令前加’sudo’,不需要输入密码就能以root身份运行.

[root@localhost sudoers.d]# su zhengtianbao
[zhengtianbao@localhost sudoers.d]$ ls
ls: cannot open directory .: Permission denied
[zhengtianbao@localhost sudoers.d]$ sudo ls
stack_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命令;且运行时不必输入密码.
一点点疑问:能否控制命令的参数呢?接下来做个测试:

[root@localhost sudoers.d]# echo 'zhengtianbao ALL = (root) NOPASSWD: /bin/ls -l, /bin/ls -a' > stack_sh
[root@localhost sudoers.d]# su zhengtianbao
[zhengtianbao@localhost sudoers.d]$ ls -a
ls: cannot open directory .: Permission denied
[zhengtianbao@localhost sudoers.d]$ sudo ls -a
.  ..  stack_sh
[zhengtianbao@localhost sudoers.d]$ sudo ls -l
total 8
-rw-r--r-- 1 root root  59 Jan 26 14:43 stack_sh
[zhengtianbao@localhost sudoers.d]$ sudo ls -a -l
[sudo] 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`` does not have a ``#includedir``, add one
grep -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 user
if [[ $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, etc
function 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 rootwrap
function 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, but did 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.

0 0