在研究与容器共享 PID 命名空间时,我注意到一些我不理解的有趣的东西。当容器与主机共享 PID 命名空间时,一些进程的环境变量受到保护,而另一些则没有。
让我们以 mysql 为例。我将启动一个带有 env 变量集的容器:
ubuntu@sandbox:~$ docker container run -it -d --env MYSQL_ROOT_PASSWORD=SuperSecret mysql
551b309513926caa9d5eab5748dbee2f562311241f72c4ed5d193c81148729a6
我将启动另一个共享主机 PID 命名空间的容器并尝试访问该environ
文件:
ubuntu@sandbox:~$ docker container run -it --rm --pid host ubuntu /bin/bash
root@1c670d9d7138:/# ps aux | grep mysql
999 18212 5.0 9.6 2006556 386428 pts/0 Ssl+ 17:55 0:00 mysqld
root 18573 0.0 0.0 2884 1288 pts/0 R+ 17:55 0:00 grep --color=auto mysql
root@1c670d9d7138:/# cat /proc/18212/environ
cat: /proc/18212/environ: Permission denied
有些东西阻止了我读取环境变量的权限。我发现我需要CAP_SYS_PTRACE
在容器中阅读它:
ubuntu@sandbox:~$ docker container run -it --rm --pid host --cap-add SYS_PTRACE ubuntu /bin/bash
root@079d4c1d66d8:/# cat /proc/18212/environ
MYSQL_PASSWORD=HOSTNAME=551b30951392MYSQL_DATABASE=MYSQL_ROOT_PASSWORD=SuperSecretPWD=/HOME=/var/lib/mysqlMYSQL_MAJOR=8.0GOSU_VERSION=1.14MYSQL_USER=MYSQL_VERSION=8.0.30-1.el8TERM=xtermSHLVL=0MYSQL_ROOT_HOST=%PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binMYSQL_SHELL_VERSION=8.0.30-1.el8
但是,并非所有进程都以这种方式受到保护。
例如,我将启动另一个容器 ubuntu 容器并设置 env 变量并运行tail
命令。
ubuntu@sandbox:~$ docker container run --rm --env SUPERSECRET=helloworld -d ubuntu tail -f /dev/null
42023615a4415cd4064392e890622530adee1f42a8a2c9027f4921a522d5e1f2
现在,当我使用共享 pid 命名空间运行容器时,我可以访问环境变量。
ubuntu@sandbox:~$ docker container run -it --rm --pid host ubuntu /bin/bash
root@3a774156a364:/# ps aux | grep tail
root 19056 0.0 0.0 2236 804 ? Ss 17:57 0:00 tail -f /dev/null
root 19176 0.0 0.0 2884 1284 pts/0 S+ 17:58 0:00 grep --color=auto tail
root@3a774156a364:/# cat /proc/19056/environ
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=42023615a441SUPERSECRET=helloworldHOME=/root
什么机制阻止我读取 mysqld 环境变量而不是tail -f
进程?
在第一种情况下,您使用不同的用户 ID 运行这一事实。如果我们启动您的两个示例:
然后看看产生的过程:
我们看到它
mysqld
以 UID 999 运行,而tail
命令以 UID 0 运行。当我们在主机 pid 命名空间中启动一个新容器时,我们只能读取environ
由相同 UID 和 GID 拥有的进程。所以这是可行的,因为默认情况下容器使用 UID 0 运行:这失败了:
如果我们有能力,我们只能读取在
environ
不同 UID 或 GID 下运行的进程的文件。CAP_SYS_PTRACE
此检查的逻辑在内核中的ptrace_may_access
函数中:我们可以通过让容器使用与 mysql 进程相同的 UID 和 GID 运行来使失败的示例工作: