什么是uid(理解)
admin
2023-09-03 23:08:26

默认情况下,容器中的进程以root权限运行,这个root用户和主机中的root是同一个用户。是不是听起来很可怕,因为这意味着容器中的进程一旦有了适当的机会,就可以控制主机上的一切!在本文中,我们将尝试了解用户名、组名、用户id(uid)和组id(gid)如何在容器中的进程和主机系统之间映射,这对系统的安全性非常重要。注:本文演示环境为ubuntu16.04(下图来自互联网)。

先来了解下uid和gid

uid和gid由Linux内核管理,一个请求是否应该被授予特权是通过内核级系统调用决定的。例如,当一个进程试图写入一个文件时,内核将检查创建进程的uid和gid,以确定它是否有足够的权限修改该文件。注意,内核使用uid和gid,而不是用户名和组名。

为简单起见,本文其余部分仅以uid为例,系统对待gid的方式与对待uid的方式相同。

很多同学把docker容器简单的理解为一个轻量级的虚拟机,这简化了理解容器技术的难度但也带来了很多误解。其实和虚拟机技术是不一样的:运行在同一个主机上的所有容器共享同一个内核(主机的内核)。容器化的巨大价值在于,所有这些独立的容器(实际上是流程)可以共享一个内核。这意味着即使docker主机上运行了数百个容器,仍然只有一组uid和gid由内核控制。所以同一个uid在主机和容器中代表同一个用户(即使不同的用户名显示在不同的地方)。

注意,由于常用的用于显示用户名的Linux工具不属于内核(比如id等命令),我们可能会看到相同的uid在不同的容器中显示为不同的用户名。但是你不能对同一个uid拥有不同的特权,即使是在不同的容器中。

如果你已经了解Linux的usernamespace技术,参考《LinuxNamespace:User》,需要注意的是,到目前为止,docker还没有默认启用usernamesapce,这也是本文讨论的情况。作者将在下一篇文章中介绍如何配置docker来启用usernamespace。

容器中默认使用root用户

如果不做相关设置,容器中的进程默认以root用户权限启动。以下演示使用ubuntu image运行睡眠程序:

注意,在上面的命令中没有使用sudo。作者在主机中的登录用户是nick,uid是1000:

查看主机中睡眠进程的信息:

睡眠进程的有效用户名是root,这意味着睡眠进程拥有root权限。

然后查看容器内部,看到与之前相同的情况。睡眠进程也有根权限:

那么,容器中的root用户和主机上的root用户是一样的吗?

答案是:是的,它们对应同一个uid。我们之前解释过的原因是整个系统共享同一个内核,内核只管理一组uid和GID。

事实上,我们可以简单地通过数据量来验证上述结论。在主机上创建一个只有root用户可以读写的文件:

然后将其安装在容器中:

该文件可以在容器中读写:

我们可以通过Dockerfile中的USER命令或者dockerrun命令的- user参数来指定容器中流程的用户标识。下面我们分别探讨这两种情况。

在Dockerfile中指定用户身份

我们可以在Dockerfile中添加一个用户appuser,并使用USER命令指定以这个用户的身份运行程序。Dockerfile的内容如下:

编译成名为test的镜像:

用测试图像启动一个容器:

查看主机中睡眠进程的信息:

这次显示的有效用户是nick,因为在主机中,uid为1000的用户名是nick。再次进入容器,看一看:

容器中的当前用户是我们设置的appuser。如果查看容器中的/etc/passwd文件,会发现appuser的uid是1000,与主机中用户nick的uid相同。

让我们创建另一个只有用户nick可以读写的文件:

还将其作为数据卷安装在容器中:

在容器中,testfile的所有者实际上变成了appuser,当然appuser也有读写文件的权利。

这里到底发生了什么?这意味着什么?

首先,主机系统中有一个uid为1000的用户nick。其次,容器中的程序运行为appuser,这是我们在Dockerfile程序中通过USERappuser命令指定的。

实际上,系统内核管理的uid1000只有一个。在主机中,它被认为是用户nick,而在容器中,它被认为是用户appuser。

所以我们需要明确一点:在容器内部,用户appuser可以获得容器外部用户nick的权利和特权。在主机上授予用户nick或uid1000的权限也将授予容器中的appuser。

从命令行参数中自定用户身份

我们还可以通过dockerrun命令的- user参数指定容器中进程的用户标识。例如,执行以下命令:

因为我们在命令行上指示了参数- user1000,所以

这里sleep进程的有效用户显示为nick。进入到容器内部看一下:

这是个什么情况?用户名称居然显示为"Ihavenoname!"!去查看/etc/passwd文件,里面果然没有uid为1000的用户。即便没有用户名称,也丝毫不影响该用户身份的权限,它依然可以读写只有nick用户才能读写的文件,并且用户信息也由uid代替了用户名:

需要注意的是,在创建容器时通过dockerrun--user指定的用户身份会覆盖掉Dockerfile中指定的值。

我们重新通过test镜像来运行两个容器:

查看sleep进程信息:

再次查看sleep进程信息:

指定了--urser0参数的进程显示有效用户为root,说明命令行参数--user0覆盖掉了Dockerfile中USER命令的设置。

总结

从本文中的示例我们可以了解到,容器中运行的进程同样具有访问主机资源的权限(docker默认并没有对用户进行隔离),当然一般情况下容器技术会把容器中进程的可见资源封锁在容器中。但是通过我们演示的对数据卷中文件的操作可以看出,一旦容器中的进程有机会访问到宿主机的资源,它的权限和宿主机上用户的权限是一样的。所以比较安全的做法是为容器中的进程指定一个具有合适权限的用户,而不要使用默认的root用户。当然还有更好的方案,就是应用Linux的usernamespace技术隔离用户,笔者会在接下来的文章中介绍如何配置docker开启usernamespace的支持。

参考:

UnderstandinghowuidandgidworkinDockercontainers

IntroductiontoUserNamespacesinDockerEngine

Isolatecontainerswithausernamespace

作者:sparkdev

首发出处:http://t.cn/Eflqt47

相关内容

热门资讯

金花创建房间/微信金花房卡怎么... 1.微信渠道:(荣耀联盟)大厅介绍:咨询房/卡添加微信:88355042 2.微信游戏中心:打开微...
金花房间卡/金花房卡如何购买/... 金花房间卡/金花房卡如何购买/新超圣金花房卡正版如何购买新超圣是一款非常受欢迎的游戏,咨询房/卡添加...
牛牛创建房间/金花房卡批发/神... 微信游戏中心:神牛大厅房卡在哪里买打开微信,添加客服【88355042】,进入游戏中心或相关小程序,...
链接牛牛/牛牛房卡游戏代理/鸿... 鸿运大厅房卡更多详情添加微:33549083、 2、在商城页面中选择房卡选项。 3、根...
科技实测!牛牛房卡怎么获得/乐... 微信游戏中心:乐酷大厅房卡在哪里买打开微信,添加客服【88355042】,进入游戏中心或相关小程序,...