用法¶
oslo.privsep 允许你在代码中定义特定的函数,这些函数将在预定义的权限上下文中运行。这让你能够以比代码其余部分更多(或更少)的权限运行函数。Privsep 函数存在于特定的 privsep 子模块中(例如,nova 的 nova.privsep)。
定义上下文¶
上下文在 privsep/__init__.py 文件中定义。例如,这定义了一个 sys_admin_pctxt,具有 CAP_CHOWN、CAP_DAC_OVERRIDE、CAP_DAC_READ_SEARCH、CAP_FOWNER、CAP_NET_ADMIN 和 CAP_SYS_ADMIN 权限(相当于 sudo 权限)
from oslo_privsep import capabilities
from oslo_privsep import priv_context
sys_admin_pctxt = priv_context.PrivContext(
'nova',
cfg_section='nova_sys_admin',
pypath=__name__ + '.sys_admin_pctxt',
capabilities=[capabilities.CAP_CHOWN,
capabilities.CAP_DAC_OVERRIDE,
capabilities.CAP_DAC_READ_SEARCH,
capabilities.CAP_FOWNER,
capabilities.CAP_NET_ADMIN,
capabilities.CAP_SYS_ADMIN],
)
定义带超时的上下文¶
可以初始化带有超时的 PrivContext
from oslo_privsep import capabilities
from oslo_privsep import priv_context
dhcp_release_cmd = priv_context.PrivContext(
__name__,
cfg_section='privsep_dhcp_release',
pypath=__name__ + '.dhcp_release_cmd',
capabilities=[caps.CAP_SYS_ADMIN,
caps.CAP_NET_ADMIN],
timeout=5
)
PrivsepTimeout 在超时达到时会被引发。
警告
守护进程(根进程)任务在超时达到时不会停止。这意味着如果相关的线程永远无法完成,我们将拥有更少的可用线程。
定义特权函数¶
函数在 privsep/ 子目录下的文件中定义,例如在 privsep/motd.py 文件中,用于处理 MOTD 文件的函数。它们使用指向我们上面定义的上下文的装饰器
import nova.privsep
@nova.privsep.sys_admin_pctxt.entrypoint
def update_motd(message):
with open('/etc/motd', 'w') as f:
f.write(message)
特权函数必须尽可能简单、专门和狭窄,以防止进一步的权限提升。在这个例子中,update_motd(message) 是狭窄的:它只允许服务覆盖 MOTD 文件。如果创建了一个更通用的 update_file(filename, content),它可能会被用来覆盖文件系统中的任何文件,从而很容易提升到 root 权限。这将破坏 oslo.privsep 的整个目的。
定义带超时的特权函数¶
可以使用 entrypoint_with_timeout 装饰器
from oslo_privsep import daemon
from neutron import privileged
@privileged.default.entrypoint_with_timeout(timeout=5)
def get_link_devices(namespace, **kwargs):
try:
with get_iproute(namespace) as ip:
return make_serializable(ip.get_links(**kwargs))
except OSError as e:
if e.errno == errno.ENOENT:
raise NetworkNamespaceNotFound(netns_name=namespace)
raise
except daemon.FailedToDropPrivileges:
raise
except daemon.PrivsepTimeout:
raise
PrivsepTimeout 在超时达到时会被引发。
警告
守护进程(根进程)任务在超时达到时不会停止。这意味着如果相关的线程永远无法完成,我们将拥有更少的可用线程。
使用特权函数¶
要在常规代码中使用特权函数,你可以直接调用它
import nova.privsep.motd
...
nova.privsep.motd.update_motd('This node is currently idle')
最好导入完整的路径(import nova.privsep.motd),而不是 motd 名称(from nova.privsep import motd),以便更容易地发现该函数在不同的特权上下文中运行。
有关更多详细信息,你可以阅读以下博客文章
从 rootwrap 转换为 privsep¶
oslo.rootwrap 是 oslo.privsep 的前身,允许代码在匹配预定义过滤器时以 sudo 身份运行命令。例如,你可以定义一个过滤器,允许你使用以下过滤器以 root 身份运行 chmod
chmod: CommandFilter, chmod, root
除了调用完整命令以完成简单任务的糟糕性能之外,rootwrap 还会导致糟糕的安全问题:很难以不会轻易允许权限提升的方式过滤命令。
用 privsep 函数替换 rootwrap 过滤器很容易。上面的 chmod 过滤器可以替换为一个调用 os.chmod() 的函数。但是,直接 1:1 的过滤器:函数替换通常会导致函数仍然过于宽泛,无法保证良好的安全性。最好将每个 chmod rootwrap 调用 替换为一个狭窄的 privsep 函数,该函数将将其限制在特定的文件上。
有时需要重构调用代码:rootwrap 设计 discouraged 创建新的过滤器,因此通常会导致创建过于宽泛的调用函数。
例如,这个 补丁系列 正在进行中,以将 Nova 从 rootwrap 转换为 privsep。
有关更多详细信息,你可以阅读以下博客文章