用户命名空间用于隔离用户和组ID的编号,它提供了一种限定范围内的超级用户权限,增加了安全性和隔离性。
本文将介绍用户命名空间的作用、层次关系和各种应用,从而更全面地了解用户命名空间。
(传统的)超级用户和设置UID为root的程序
传统的方式给非特权用户赋予特权的方法是通过将程序的UID设置为root
传统的方式给 “非特权用户”赋予特权的方法是通过 “将程序的UID设置为root”。通常情况下,只有 “具有root权限的” 用户才能执行某些特权操作,例如更改系统设置或访问受限资源。然而,通过设置一个程序的UID为root,即使是普通用户执行该程序时,也会 “临时获得” 与root相同的权限,从而能够执行一些特权操作。
这种方式虽然可以实现 “特权提升”,但也存在安全风险,因为程序可能被滥用或攻击者利用。
传统的特权模型存在问题
Capabilities 是试图解决这个问题的一种方式
能力(capabilities)
与设置UID为root的程序不同,使用“附加了一项/几项能力的程序”可以更细粒度的控制和分配权限,从而提高安全性和灵活性
例如,通过执行sudosetcap cap_net_raw+ep /home/test/myprog, 授予程序 myprog 网络访问能力,它可以在“不需要 root 权限下”打开原始套接字进行通信。
因此,进程可以拥有能力(root权限的部分子集);文件可以附加能力,这些能力可以授予执行程序的进程 ;如果使用能力来实现特权二进制文件或进程,那么即使被攻击,它们的威胁性也较小。
What do user namespaces do?
一个有趣的用例是,进程在命名空间外可能具有非零的UlD,而在命名空间内,它的UlD可能是0。
用户命名空间的关系
父子关系决定了某些关于权限管理的规则。
示例:创建一个具有"root"映射的用户命名空间
这里,有一个“非特权用户 UID 1001, GID 1001”,它的 CapEff 为0,即它在初始命名空间是没有任何特权或权限的。(CapEff 就是用户所拥有的能力。)
使用“非特权用户 UID 1001, GID 1001”,创建了一个新的用户命名空间,并在该命名空间运行 bash。
这里运行的 unshare 会将一些字符串写入 uid_map 和 gid_map,表示将“新用户命名空间的uid 0”映射到“父用户命名空间的uid 1001”,范围为 1。
它的CapEff 为0x1fffffffff ,0x1fffffffff 是一个位掩码,其中包含了所有 38 个能力位的设置。
既然“用户UID 1001”在新用户命名空间具有超级用户权限,那么它能做什么呢?
如下所示,改变主机名需要 CAP_SYS_ADMIN 权限,它已经具备了,那为什么还是失败?
因为,新的 shell 在新用户命名空间中,但仍然驻留在“初始UTS命名空间”中,请记住,主机名是由“UTS 命名空间”隔离和管理的。
内核会授予新用户命名空间的初始进程的所有能力,但是,这些能力仅仅适用于新用户命名空间管理的对象的操作。
再举个例子说明一下:使用unshare -Ur -u
创建了 X
假设X 尝试更改主机名(CAP_SYS_ADMIN)
假设 X尝试绑定到保留的套接字端口(CAPNET_BINDSERVICE)
总之呢,先判断进程位于哪个命名空间中,然后再判断在这个命名空间中用户的能力,有相应的能力,才能进行相应的操作。
用户命名空间一些新的应用
用户命名空间允许一些新颖的应用程序;以下是例子:
无需“LD_PRELOAD 动态链接技巧的 fakeroot 类型应用程序”
Firejail:使用 namespaces + seccomp + capabilities (特权)的功能,可以对任何应用程序实现通用且简化的沙盒化。
Flatpak:使用namespaces +seccomp + capabilities + cgroups来进行应用程序打包和沙盒化。
桌面应用程序在图形用户界面中无缝运行。
chroot()系统调用可以将“进程的根目录”更改为“指定的目录”,从而创建一个“虚拟的根文件系统环境”。基于这个特性,可以利用chroot()来实现进程的隔离,使其在一个“受限的文件系统视图”中运行,而不会访问实际的根文件系统。
例如,在一个多租户的环境中,可以使用chroot()来隔离“不同的用户或组织”之间的进程,使它们只能访问自己的受限文件系统,从而互相隔离,减少潜在的安全风险。
使用“用户命名空间+ chroot ”组合的方式为:“非特权进程”创建一个“用户命名空间”,并使用chroot()将其“根目录”切换到“新的命名空间中的特定目录”。
通过这种方式,非特权进程可以实现一定程度的“容器化或沙盒化”效果。这对于安全性要求较高或需要隔离应用程序的场景非常有用,例如运行第三方代码、进行软件开发和测试等。
fakeroot是一个工具,可以“模拟特权(root)用户”的环境,让“非特权用户”在其中“执行需要特权权限的任务”。通常情况下,为了实现这一功能,需要使用LD_PRELOAD来加载额外的库,或者进行动态链接技巧来修改程序运行时的行为。
但是,在用户命名空间中,可以通过“创建新的用户命名空间”并使用“chroot()”来实现类似的效果,而不需要依赖LD_PRELOAD或动态链接技巧。
沙盒化是一种安全机制,通过“隔离应用程序的运行环境”,“限制”其访问系统资源和敏感文件,从而提高系统的安全性。Firejail提供了一种轻量级的方式来创建和管理沙盒,使得应用程序“在沙盒中运行时受到限制”并“无法操作主机系统的其他部分”。
Firejail使用命名空间(namespaces)来“隔离不同进程之间的资源”,包括文件系统、网络、进程间通信等;使用 seccomp(Secure ComputingMode)来“限制”应用程序“可以使用的系统调用”,它过滤掉不必要或危险的系统调用,从而减少潜在的安全风险;通过特权功能(capabilities)来管理应用程序的权限,通过细粒度地控制特权功能,Firejail可以确保应用程序仅能执行它们需要的操作,而不会超出其权限范围。
Flatpak(扁平包)是一种用于Linux系统的应用程序打包和沙盒化技术。它基于命名空间(namespaces)、seccomp、特权(capabilities)和cgroups等功能,旨在提供一种通用的方式,供开发者将应用程序打包并提供所有必要的运行时依赖项。这意味着应用程序不再需要依赖于特定的发行版或系统配置,而是可以在任何支持Flatpak 的Linux发行版上运行。
当谈到Flatpak(扁平包)提供沙箱时,可以将其类比为一个“隔离的盒子”,其中应用程序可以安全地运行,而不会对主机系统产生负面影响。与之类似的技术是Docker,但在处理GUI应用程序时并不太理想。相比之下,Flatpak 可以实现无缝集成 GUI应用程序到桌面环境中,就好像直接安装在主机上,你可以在任务栏或应用程序菜单中找到它们。
命名空间和其他技术被广泛运用在Flatpak 中,以实现这种“魔法”般的体验。这些技术最初是为容器技术设计的,但现在被创造性地应用在其他领域。
Docker是一种用于构建和管理容器的流行技术,它在许多场景下非常强大和有效。然而,当涉及到GUI应用程序时,Docker 并不是一个理想的选择。以下是两个原因:
1、缺乏图形显示支持:Docker 的设计初衷是为了运行无需图形交互的服务和应用程序。因此,它并没有内置对图形显示的全面支持。虽然可以通过一些技巧将图形显示传递到Docker 容器中,但这往往需要额外的配置和复杂的步骤。
2、限制了设备访问:Docker在默认情况下会限制容器对主机系统设备的访问权限,包括图形和输入设备。这意味着 GUI应用程序可能无法访问或使用必要的图形和输入设备,从而导致功能受限或无法正常工作。
相比之下,Flatpak就是专门为了提供图形用户界面应用程序的支持而设计的。
参考: