컨테이너와 PID 네임스페이스를 공유하는 방법을 연구하는 동안 제가 이해하지 못하는 흥미로운 사실을 발견했습니다. 컨테이너가 호스트와 PID 네임스페이스를 공유하면 일부 프로세스의 환경 변수는 보호되지만 다른 프로세스는 보호되지 않습니다.
mysql을 예로 들어보자. 환경 변수 세트를 사용하여 컨테이너를 시작하겠습니다.
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
?
답변1
tail -f 프로세스 대신 mysqld 환경 변수를 읽지 못하게 하는 메커니즘은 무엇입니까?
실제로 첫 번째 경우에는 다른 사용자 ID로 실행 중입니다. 두 가지 예를 시작하면 다음과 같습니다.
docker run --name mysql -it -d --env MYSQL_ROOT_PASSWORD=SuperSecret mysql:latest
docker run --name tail -it -d --env MYSQL_ROOT_PASSWORD=SuperSecret ubuntu:latest tail -f /dev/null
그런 다음 생성 프로세스를 살펴보십시오.
$ ps -fe n |grep -E 'tail|mysqld' | grep -v grep
999 422026 422005 2 22:50 pts/0 Ssl+ 0:00 mysqld
0 422170 422144 0 22:50 pts/0 Ss+ 0:00 tail -f /dev/null
mysqld
UID 999로 실행되고 명령은 tail
UID 0으로 실행되는 것을 볼 수 있습니다 . 호스트 pid 네임스페이스에서 새 컨테이너를 시작하면 environ
동일한 UID 및 GID가 소유한 프로세스만 읽을 수 있습니다. 컨테이너가 기본적으로 UID 0으로 실행되기 때문에 이는 작동합니다.
$ docker run --rm --pid host ubuntu:latest cat /proc/422170/environ | tr '\0' '\n'
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=e89c069d4674
TERM=xterm
MYSQL_ROOT_PASSWORD=SuperSecret
HOME=/root
실패합니다.
$ docker run --rm --pid host ubuntu:latest cat /proc/422026/environ | tr '\0' '\n'
cat: /proc/422026/environ: Permission denied
능력이 있다면 environ
다른 UID 또는 GID에서 실행되는 프로세스에서만 파일을 읽을 수 있습니다 CAP_SYS_PTRACE
. 이 검사의 논리는 다음 위치에 있습니다.ptrace_may_access
기능커널에서:
if (uid_eq(caller_uid, tcred->euid) &&
uid_eq(caller_uid, tcred->suid) &&
uid_eq(caller_uid, tcred->uid) &&
gid_eq(caller_gid, tcred->egid) &&
gid_eq(caller_gid, tcred->sgid) &&
gid_eq(caller_gid, tcred->gid))
goto ok;
if (ptrace_has_cap(tcred->user_ns, mode))
goto ok;
mysql 프로세스와 동일한 UID 및 GID를 사용하여 컨테이너를 실행하면 이 실패한 예제가 작동하도록 할 수 있습니다.
$ docker run -u 999:999 --rm --pid host ubuntu:latest cat /proc/422026/environ | tr '\0' '\n'
MYSQL_PASSWORD=
HOSTNAME=bde980104dcd
MYSQL_DATABASE=
MYSQL_ROOT_PASSWORD=SuperSecret
PWD=/
HOME=/var/lib/mysql
MYSQL_MAJOR=8.0
GOSU_VERSION=1.14
MYSQL_USER=
MYSQL_VERSION=8.0.31-1.el8
TERM=xterm
SHLVL=0
MYSQL_ROOT_HOST=%
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MYSQL_SHELL_VERSION=8.0.31-1.el8