文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

理解 Docker 容器中 UID 和 GID 的工作原理

2024-11-30 01:16

关注

逐步分析uid/gid安全性

首先,让我们回顾一下uid和gid是如何实现的。Linux内核负责管理uid和gid空间,使用内核级系统调用来确定是否应该授予请求的特权。例如,当一个进程尝试写入文件时,内核会检查创建该进程的uid和gid,以确定它是否具有足够的特权来修改文件。这里不使用用户名,而是使用uid。

在服务器上运行 Docker 容器时,仍然只有一个内核。容器化带来的巨大价值之一是所有这些独立的进程可以继续共享一个内核。这意味着即使在运行 Docker 容器的服务器上,整个 uid 和 gid 的世界仍由一个单一内核控制。

因此,在不同的容器中不能使用相同的 uid 分配给不同的用户。这是因为在常见的 Linux 工具中显示的用户名(和组名)并不是内核的一部分,而是由外部工具(如 /etc/passwd、LDAP、Kerberos 等)管理。因此,你可能会看到不同的用户名,但是即使在不同的容器中,对于相同的 uid/gid,你也不能拥有不同的权限。这一点一开始可能会让人感到相当困惑,所以让我们通过几个例子来说明一下:

简单的Docker运行

我将首先以普通用户(marc)的身份登录到一个属于docker组的服务器上。这样我就可以在不使用sudo命令的情况下启动docker容器。然后,从容器外部,让我们来看看这个过程是如何呈现的。

marc@server:~$ docker run -d ubuntu:latest sleep infinity
92c57a8a4eda60678f049b906f99053cbe3bf68a7261f118e411dee173484d10
marc@server:~$ ps aux | grep sleep
root 15638 0.1 0.0 4380 808 ? Ss 19:49 0:00 sleep infinity

尽管我从未输入过sudo,也不是root用户,但我执行的sleep命令以root用户身份启动并具有root权限。我如何知道它具有root权限?容器内的root是否等同于容器外的root?是的,因为正如我提到的,有一个单一的内核和一个共享的uid和gid池。由于容器外显示的用户名是“root”,我可以确定容器内的进程是以具有uid = 0的用户启动的。

带有定义用户的Dockerfile

当我在 Dockerfile 中创建一个不同的用户并以该用户身份启动命令时会发生什么?为了简化这个例子,我这里没有指定 gid,但相同的概念也适用于组 id。

首先,我正在以用户名为“marc”的用户身份运行这些命令,该用户的用户ID为1001。

marc@server:~$ echo $UID
1001

Dockerfile文件:

FROM ubuntu:latest
RUN useradd -r -u 1001 -g appuser appuser
USER appuser
ENTRYPOINT [“sleep”, “infinity”]

构建:

marc@server:~$ docker build -t test .
Sending build context to Docker daemon 14.34 kB
Step 1/4 : FROM ubuntu:latest
 — -> f49eec89601e
Step 2/4 : RUN useradd -r -u 1001 appuser
 — -> Running in 8c4c0a442ace
 — -> 6a81547f335e
Removing intermediate container 8c4c0a442ace
Step 3/4 : USER appuser
 — -> Running in acd9e30b4aba
 — -> fc1b765e227f
Removing intermediate container acd9e30b4aba
Step 4/4 : ENTRYPOINT sleep infinity
 — -> Running in a5710a32a8ed
 — -> fd1e2ab0fb75
Removing intermediate container a5710a32a8ed
Successfully built fd1e2ab0fb75
marc@server:~$ docker run -d test
8ad0cd43592e6c4314775392fb3149015adc25deb22e5e5ea07203ff53038073
marc@server:~$ ps aux | grep sleep
marc 16507 0.3 0.0 4380 668 ? Ss 20:02 0:00 sleep infinity
marc@server:~$ docker exec -it 8ad0 /bin/bash
appuser@8ad0cd43592e:/$ ps aux | grep sleep
appuser 1 0.0 0.0 4380 668 ? Ss 20:02 0:00 sleep infinity

这里到底发生了什么,这意味着什么?我构建了一个 Docker 镜像,其中有一个名为“appuser”的用户,该用户的 uid 为 1001。在我的测试服务器上,我使用的帐户名为“marc”,uid 也是 1001。当我启动容器时,sleep 命令以 appuser 的身份执行,因为 Dockerfile 包含了“USER appuser”这一行。但实际上这并不是以 appuser 的身份运行,而是以 Docker 镜像中被识别为 appuser 的用户的 uid 运行。

当我检查容器外运行的进程时,我发现它映射到用户“marc”,但在容器内部,它映射到用户“appuser”。这两个用户名只是显示它们的执行上下文所知道的映射到1001的用户名。

这并不是非常重要。但重要的是要知道,在容器内部,用户“appuser”获得了来自容器外部用户“marc”的权限和特权。在Linux主机上授予用户marc或uid 1001的权限也将授予容器内的appuser这些权限。

如何控制容器的访问权限

另一种选择是在运行 Docker 容器时指定用户名或用户ID,以及组名或组ID。

再次使用上面的初始示例。

marc@server:~$ docker run -d --user 1001 ubuntu:latest sleep infinity
84f436065c90ac5f59a2256e8a27237cf8d7849d18e39e5370c36f9554254e2b
marc@server$ ps aux | grep sleep
marc     17058 0.1 0.0 4380 664 ? Ss 21:23 0:00 sleep infinity

我在这里做了什么?我创建了容器以1001用户身份启动。因此,当我执行诸如ps或top(或大多数监控工具)之类的命令时,进程映射到“marc”用户。

有趣的是,当我进入该容器时,你会发现1001用户在/etc/passwd文件中没有条目,并在容器的bash提示符中显示为“I have no name!”。

marc@server:~$ docker exec -it 84f43 /bin/bash
I have no name!@84f436065c90:/$

重要的是要注意,在创建容器时指定用户标志也会覆盖 Dockerfile 中的值。还记得第二个例子吗?那时我使用了一个 Dockerfile,其中的 uid 映射到本地主机上的不同用户名。当我们在命令行上使用用户标志来启动一个执行“sleep infinity”进程的容器时,会发生什么呢?

marc@server:$ docker run -d test
489a236261a0620e287e434ed1b15503c844648544694e538264e69d534d0d65
marc@server:~$ ps aux | grep sleep
marc     17689 0.2 0.0 4380 680 ? Ss 21:28 0:00 sleep infinity
marc@server:~$ docker run --user 0 -d test
ac27849fcbce066bad37190b5bf6a46cf526f56d889af61e7a02c3726438fa7a
marc@server:~$ ps aux | grep sleep
marc     17689 0.0 0.0 4380 680 ? Ss 21:28 0:00 sleep infinity
root     17783 0.3 0.0 4380 668 ? Ss 21:28 0:00 sleep infinity

在上面的最后一个示例中,您可以看到我最终得到了两个运行睡眠进程的容器,一个是“marc”,另一个是“root”。这是因为第二个命令通过在命令行上传递--user标志来更改了用户ID。

总结

现在我们已经探讨了这一点,可以理解以有限权限运行容器的方式都利用了主机的用户系统:

来源:云原生运维圈内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯