用法

Rootwrap 应该作为一个独立的 Python 进程调用 oslo_rootwrap.cmd:main 函数。你可以设置一个特定的控制台脚本调用 oslo_rootwrap.cmd:main,例如命名为 nova-rootwrap。为了保持简单,本文档将认为你的控制台脚本名为 /usr/bin/nova-rootwrap

rootwrap 命令行应该在 sudo 下调用。它的第一个参数是使用的配置文件,其余参数是要执行的命令行

sudo nova-rootwrap ROOTWRAP_CONFIG COMMAND_LINE

rootwrap 的工作原理

OpenStack 服务通常在特定的非特权用户下运行。但是,有时它们需要以 root 用户身份运行命令。与其直接调用 sudo make me a sandwich 并拥有一个允许从其非特权用户到 root 用户的 blanket sudoers 权限,不如这些服务调用 sudo nova-rootwrap /etc/nova/rootwrap.conf make me a sandwich

一个 sudoers 条目允许非特权用户以 root 身份运行 nova-rootwrapnova-rootwrap 在其配置文件中查找过滤器定义目录,并从中加载命令过滤器。然后它检查 OpenStack 服务请求的命令是否与这些过滤器中的一个匹配,在这种情况下它将执行该命令(以 root 身份)。如果没有过滤器匹配,它将拒绝该请求。这允许对允许的命令进行复杂的过滤,以及将过滤器定义与需要它们的代码一起打包。

安全模型

升级路径完全由 root 用户控制。一个 sudoers 条目(由 root 用户拥有)允许非特权用户以 root 身份运行特定的 rootwrap 可执行文件,并且仅使用特定的配置文件(应该由 root 用户拥有)作为其第一个参数。

nova-rootwrap 从清理后的(和系统默认的)PYTHONPATH 导入它需要的 Python 模块。配置文件指向 root 拥有的过滤器定义目录,其中包含 root 拥有的过滤器定义文件。这个链条确保非特权用户本身从不控制 nova-rootwrap 可执行文件使用的配置或模块。

安装

希望运行 nova-rootwrap 的所有节点都应该包含一个 sudoers 条目,允许非特权用户以 root 身份运行 nova-rootwrap,指向 root 拥有的 rootwrap.conf 配置文件,并允许其后的任何参数。例如,Nova 节点应该在其 sudoers 文件中包含以下行,以允许 nova 用户调用 sudo nova-rootwrap

nova ALL = (root) NOPASSWD: /usr/bin/nova-rootwrap /etc/nova/rootwrap.conf *

然后该节点还应该提供与它使用 nova-rootwrap 对应的过滤器定义。你不应该在节点上安装任何其他过滤器文件,否则你将允许额外的、不必要的命令以 root 身份运行。

与节点对应的过滤器文件必须安装在 filters_path 目录之一中。例如,在 Nova 计算节点上,你只应该安装 compute.filters。该文件应该仅由 root 用户拥有和可写。

Rootwrap 配置

rootwrap.conf 文件用于影响 nova-rootwrap 的工作方式。由于它位于受信任的安全路径中,因此它需要由 root 用户拥有和可写。它的位置在 sudoers 条目中指定,并且必须作为 nova-rootwrap 命令行的第一个参数提供。

rootwrap.conf 使用 INI 文件格式,包含以下部分和参数

[DEFAULT] 部分

filters_path

包含过滤器定义文件的目录的逗号分隔列表。列出的所有目录必须由 root 用户拥有且只能由其写入。这是唯一的强制参数。示例:filters_path=/etc/nova/rootwrap.d,/usr/share/nova/rootwrap

exec_dirs

如果过滤器没有显式指定完整路径,则在其中搜索可执行文件的目录的逗号分隔列表。如果未指定,则默认为系统的 PATH 环境变量。列出的所有目录必须由 root 用户拥有且只能由其写入。示例:exec_dirs=/sbin,/usr/sbin,/bin,/usr/bin

use_syslog

启用 syslog 日志记录。默认值为 False。示例:use_syslog=True

syslog_log_facility

用于 syslog 日志记录的 syslog facility。有效值包括 authauthprivsysloguser0user1… 默认值为 syslog。示例:syslog_log_facility=syslog

syslog_log_level

要记录的消息。 INFO 表示记录所有用法,ERROR 表示仅记录不成功的尝试。示例:syslog_log_level=ERROR

rlimit_nofile

指定 oslo rootwrap 及其子进程使用的打开文件描述符数量的 rlimit。这在为调用进程配置了过大的 ulimit 的情况下很有用,不应将其继承给 oslo.rootwrap 及其调用的进程。不会尝试提高限制。默认值为 1024。

在不提供“/proc/self/fd”(例如,非 Linux)的平台上忽略。

.filters 文件

过滤器定义文件包含 nova-rootwrap 将用于允许或拒绝特定命令的过滤器列表。它们通常以 .filters 为后缀。由于它们位于受信任的安全路径中,因此它们需要由 root 用户拥有和可写。它们的位置在 rootwrap.conf 文件中指定。

它使用 INI 文件格式,包含一个 [Filters] 部分和多行,每行都有一个唯一的参数名称(对于你定义的每个过滤器不同)

[Filters] 部分

filter_name(每个过滤器不同)

包含首先使用要使用的过滤器类,然后是该过滤器参数(具体取决于所选的过滤器类)的逗号分隔列表。示例:kpartx: CommandFilter, /sbin/kpartx, root

可用的过滤器类

CommandFilter

基本过滤器,仅检查调用的可执行文件。参数是

  1. 允许的可执行文件

  2. 运行命令的用户

示例:允许以 root 用户身份运行 kpartx,并使用任何参数

kpartx: CommandFilter, kpartx, root

RegExpFilter

通用过滤器,首先检查调用的可执行文件,然后使用正则表达式列表来检查所有后续参数。参数是

  1. 允许的可执行文件

  2. 运行命令的用户

  3. (以及后续)用于匹配第一个(和后续)命令参数的正则表达式

示例:允许运行 /usr/sbin/tunctl,但仅在三个参数的情况下,前两个参数为 -b 和 -t

tunctl: RegExpFilter, /usr/sbin/tunctl, root, tunctl, -b, -t, .*

PathFilter

通用过滤器,允许你检查作为参数提供的路径是否落在给定的目录之下。参数是

  1. 允许的可执行文件

  2. 运行命令的用户

  3. (以及后续)命令参数。

有三种类型的命令参数:pass 将接受任何参数值,字符串将仅接受相应的字符串作为参数,除非该字符串以“/”开头,在这种情况下它将接受解析为相应目录的任何路径。

示例:允许将 /var/lib/images 下的任何文件 chown 到“nova”用户

chown: PathFilter, /bin/chown, root, nova, /var/lib/images

EnvFilter

允许调用代码设置额外环境变量的过滤器。参数是

  1. env

  2. 运行命令的用户

  3. (以及后续)可以设置的环境变量的名称,后跟 =

  4. 允许的可执行文件

示例:允许以 root 身份运行 CONFIG_FILE=foo NETWORK_ID=bar dnsmasq ...

dnsmasq: EnvFilter, env, root, CONFIG_FILE=, NETWORK_ID=, dnsmasq

ReadFileFilter

特定过滤器,允许你使用 catroot 身份读取文件。参数是

  1. 要作为 root 用户读取的文件的路径。

示例:允许以 root 身份运行 cat /etc/iscsi/initiatorname.iscsi

read_initiator: ReadFileFilter, /etc/iscsi/initiatorname.iscsi

KillFilter

特定于 kill 的过滤器,在允许该命令之前会检查受影响的进程和发送的信号。参数是

  1. 运行 kill 的用户

  2. 仅影响正在运行该可执行文件的进程

  3. (以及后续)允许发送的信号

示例:允许发送 -9-HUP 信号到 /usr/sbin/dnsmasq 进程

kill_dnsmasq: KillFilter, root, /usr/sbin/dnsmasq, -9, -HUP

IpFilter

特定于 ip 的过滤器,允许运行任何 ip 命令,但 ip netns 除外(在这种情况下,它仅允许 list、add 和 delete 子命令)。参数是

  1. ip

  2. 运行 ip 的用户

示例:允许运行任何 ip 命令,但 ip netns execip netns monitor 除外

ip: IpFilter, ip, root

IpNetnsExecFilter

特定于 ip 的过滤器,允许在 ip netns exec 下运行任何其他允许的命令。指定给 ip netns exec 的命令必须匹配另一个过滤器,此过滤器才能接受它。参数是

  1. ip

  2. 运行 ip 的用户

示例:允许运行 ip netns exec <namespace> <command>,只要 <command> 匹配另一个过滤器

ip: IpNetnsExecFilter, ip, root

ChainingRegExpFilter

如果其参数的开头与正则表达式列表匹配,并且剩余参数是任何其他允许的命令,则允许运行前缀命令的过滤器。参数是

  1. 允许的可执行文件

  2. 运行命令的用户

  3. (以及后续)用于匹配第一个(和后续)命令参数的正则表达式。

此过滤器将正则表达式列表的长度视为要检查的参数数量,其余部分由其他过滤器检查。

示例:允许运行 /usr/bin/nice,但仅当前两个参数为 -n 和整数,并且之后跟随其他过滤器允许的任何命令时

nice: ChainingRegExpFilter, /usr/bin/nice, root, nice, -n, -?\d+

注意:此过滤器不能用于强制子命令始终在 prefix 命令下运行。特别是,它不能强制某个命令仅在“nice”下运行,因为子命令可以直接显式调用。

从 OpenStack 服务调用 rootwrap

独立模式(sudo 方式)

oslo.processutils 库附带了一个方便的 execute() 函数,如果使用以下参数调用,则可用于以 root 身份调用 shell 命令

run_as_root=True

root_helper='sudo nova-rootwrap /etc/nova/rootwrap.conf

注意:某些服务附带一个 utils.execute() 方便函数,该函数会自动根据 rootwrap_config 参数的值设置 root_helper,因此只需要设置 run_as_root=True 即可。

如果您想以 root 身份调用先前未授权的命令,您还需要修改过滤器(通常在源代码树的 etc/rootwrap.d 下),以便您想要以 root 身份运行的命令实际上会被 nova-rootwrap 允许。

守护进程模式

自 1.3.0 版本起,oslo.rootwrap 支持“守护进程模式”。在这种模式下,rootwrap 将启动,读取配置文件并等待以 root 权限运行命令。所有与守护进程的通信都应通过位于 oslo_rootwrap.client 模块中的 Client 类进行。

它的构造函数需要一个参数 - 一个可以传递给 Popen 以创建 rootwrap 守护进程过程的列表。对于上面的 root_helper,它将是 ["sudo", "nova-rootwrap-daemon", "/etc/neutron/rootwrap.conf"],例如。请注意,它使用一个单独的脚本,该脚本指向 oslo_rootwrap.cmd:daemon 端点(而不是 :main)。

该类提供一个名为 execute 的方法,其参数如下

  • userargs - 用于运行命令的命令行参数列表;

  • stdin - 要传递给子进程标准输入的字符串。

该方法返回一个 3 元组,包含

  • 子进程的返回码;

  • 从其 stdout 流捕获的所有内容的字符串;

  • 从其 stderr 流捕获的所有内容的字符串。

该类延迟创建守护进程的一个实例,连接到它并传递参数。如果该守护进程死亡或被杀死,Client 将根据需要重新生成它和/或重新连接到它。