逐步分析uid/god安全性
简单的Docker运行
我将首先以 docker 组中的普通用户(marc)身份登录服务器。这允许我在不使用 sudo 命令的情况下启动 docker 容器。然后,从容器外部,让我们看看这个过程是如何出现的。
marc@server:~$ docker run -d ubuntu:latest sleep infinity92c57a8a4eda60678f049b906f99053cbe3bf68a7261f118e411dee173484d10marc@server:~$ ps aux | grep sleeproot 15638 0.1 0.0 4380 808 ? Ss 19:49 0:00 sleep infinity复制代码
有趣。即使我从未输入 sudo 并且我不是 root 用户,我执行的 sleep 命令也以root 用户身份启动并具有 root 权限。我怎么知道它有 root 权限?容器内的 root = =容器外的 root 吗?是的,因为正如我所提到的,有一个内核和一个共享的 uids 和 gids 池。因为用户名在容器外部显示为“root”,所以我可以肯定地知道容器内的进程是由具有uid = 0的用户启动的。
具有已定义用户的Dockerfile
当我在 Dockerfile 中创建不同的用户并以该用户身份启动命令时会发生什么?为了简化这个例子,我没有在这里指定一个gid,但同样的概念适用于组ID.
首先,我将这些命令作为用户“marc”运行,其 uid 为1001。
marc@server:~$ echo $UID1001复制代码
和 Dockerfile:
FROM ubuntu:latestRUN useradd -r -u 1001 -g appuser appuserUSER appuserENTRYPOINT [“sleep”, “infinity”]复制代码
让我们构建并运行它:
marc@server:~$ docker build -t test .Sending build context to Docker daemon 14.34 kBStep 1/4 : FROM ubuntu:latest — -> f49eec89601eStep 2/4 : RUN useradd -r -u 1001 appuser — -> Running in 8c4c0a442ace — -> 6a81547f335eRemoving intermediate container 8c4c0a442aceStep 3/4 : USER appuser — -> Running in acd9e30b4aba — -> fc1b765e227fRemoving intermediate container acd9e30b4abaStep 4/4 : ENTRYPOINT sleep infinity — -> Running in a5710a32a8ed — -> fd1e2ab0fb75Removing intermediate container a5710a32a8edSuccessfully built fd1e2ab0fb75marc@server:~$ docker run -d test8ad0cd43592e6c4314775392fb3149015adc25deb22e5e5ea07203ff53038073marc@server:~$ ps aux | grep sleepmarc 16507 0.3 0.0 4380 668 ? Ss 20:02 0:00 sleep infinitymarc@server:~$ docker exec -it 8ad0 /bin/bashappuser@8ad0cd43592e:/$ ps aux | grep sleepappuser 1 0.0 0.0 4380 668 ? Ss 20:02 0:00 sleep infinity复制代码
如何控制容器的访问权限
marc@server:~$ docker run -d --user 1001 ubuntu:latest sleep infinity84f436065c90ac5f59a2256e8a27237cf8d7849d18e39e5370c36f9554254e2bmarc@server$ ps aux | grep sleepmarc 17058 0.1 0.0 4380 664 ? Ss 21:23 0:00 sleep infinity复制代码
marc@server:~$ docker exec -it 84f43 /bin/bashI have no name!@84f436065c90:/$复制代码
需要注意的是,在创建容器时指定用户标志也会覆盖 Dockerfile 中的该值。还记得第二个例子,我使用的 Dockerfile 有一个映射到本地主机上不同用户名的uid吗?当我们在命令行上使用用户标志运行它以启动执行“睡眠无限”过程的容器时会发生什么?
marc@server:$ docker run -d test489a236261a0620e287e434ed1b15503c844648544694e538264e69d534d0d65marc@server:~$ ps aux | grep sleepmarc 17689 0.2 0.0 4380 680 ? Ss 21:28 0:00 sleep infinitymarc@server:~$ docker run --user 0 -d testac27849fcbce066bad37190b5bf6a46cf526f56d889af61e7a02c3726438fa7amarc@server:~$ ps aux | grep sleepmarc 17689 0.0 0.0 4380 680 ? Ss 21:28 0:00 sleep infinityroot 17783 0.3 0.0 4380 668 ? Ss 21:28 0:00 sleep infinity复制代码
在上面的最后一个例子中,你可以看到我最终有2个容器运行睡眠过程,一个用作“marc”,另一个用作“root”。这是因为第二个命令通过--user 在命令行上传递标志来更改uid.
这意味着什么?
1、如果已知的 uid 表示容器内的进程正在执行,则可能就像限制对主机系统的访问一样简单,以便容器中的 uid 有有限的访问权限。
2、更好的解决方案是使用已知的 uid 启动容器--user(您也可以使用用户名,但请记住,它只是从主机的用户名系统提供uid的更友好的方式),然后限制对主机上的 uid 的访问你决定容器将运行为。
3、由于 uid 和用户名(以及gid和组名称)如何从容器映射到主机,因此指定容器化进程运行的用户可以使进程看起来由内部和容器外部的不同用户拥有。
注意这些测试
- end -
作者:Marc Campbell
本文转载于外网,转载请标明出处