Docker(容器)cgroup/namespace setup vs 运行 Dockerfile 命令作为 root?
Docker(containers) cgroup/namespace setup vs running Dockerfile commands as root?
根据我的理解,docker 设置所需的 cgroup 和命名空间的 so 容器(即容器进程)运行 隔离(主机系统上的隔离环境)并且具有有限的权限和访问权限主机系统。因此,即使该进程 运行 在容器中以 root 身份运行,它在主机系统上也不具有 root 访问权限。
但是从这篇文章:processes-in-containers-should-not-run-as-root,我看到容器进程 运行 仍然可以作为 root 访问主机系统上只能由 root 访问的主机文件.
在主机系统上:
root@srv:/root# ls -l
total 4
-rw------- 1 root root 17 Sep 26 20:29 secrets.txt
Dockerfile -
FROM debian:stretch
CMD ["cat", "/tmp/secrets.txt"]
在运行上面Dockerfile对应的镜像上,
marc@srv:~$ docker run -v /root/secrets.txt:/tmp/secrets.txt <img>
top secret stuff
如果,top secret stuff
是可读的,怎么可能。那么容器隔离的意义何在。我还缺什么,好像还缺什么。
(与我使用 docker run
的方式有关,默认情况下,所有 permissions/capabilities 都根据用户 运行 宁 docker run
命令提供给容器.
容器只有在操作员明确授予它访问权限的情况下才能访问主机文件系统。例如,在没有任何 docker run -v
选项的情况下尝试 :
docker run \
--rm \ # clean up the container when done
-u root \ # explicitly request root user
busybox \ # image to run
cat /etc/shadow # dumps the _container's_ password file
更一般地说,规则(在没有用户命名空间重新映射的本机 Linux 上)是,如果文件从主机绑定安装到容器中,则如果容器的 numeric 用户或组 ID 与文件的所有权和权限相匹配。如果一个文件在模式为0600的主机上由uid 1000拥有,则它可以被容器中的uid 0或1000读取,而不管对应的容器和主机用户名。
由此得出的结论是,任何可以 运行 任何 docker run
命令的人都可以轻松地对整个主机进行 root。
docker run \
--rm \
-u root \
-v /:/host \ # bind-mount the host filesystem into the container
busybox \
cat /host/etc/shadow # dumps the host's encrypted password file
容器中的 root 用户进一步受到 Linux 功能的限制:如果不提供额外的特殊 Docker 选项,即使 运行 以 root 用户身份,容器也无法更改文件系统挂载、修改网络配置、加载内核模块、重启主机,或者做其他一些额外特权的事情。 (而且通常在容器外做这些事情比给Docker额外的权限更好;不要随便运行容器--privileged
。)
运行 容器作为非 root 用户通常是更好的做法。用户 ID 不需要特别匹配任何用户 ID,它只需要不是 0(匹配特定主机 uid 不能跨主机移植,因此不推荐)。容器中的文件一般应该为root所有,才不会被不小心覆盖。
FROM debian
# Create the non-root user
RUN adduser --system --no-create-home nonroot
# Do the normal installation, as root
COPY ... # no --chown option
RUN ... # does not run chown either
# Specify the non-root user only for the final container
EXPOSE 12345
USER nonroot
CMD the main container command
如果容器确实需要读取或(特别是)写入主机文件,请将主机目录绑定挂载到容器中的某个数据特定目录中(不要用此挂载覆盖应用程序代码)并使用 docker run -u
选项指定容器需要的主机 uid 运行 作为。用户不需要特别存在于容器的 /etc/passwd
文件中。
docker run \
-v "$PWD:/app/data" \ # bind-mount the current directory as data
-u $(id -u) \ # specify the user ID to use
...
根据我的理解,docker 设置所需的 cgroup 和命名空间的 so 容器(即容器进程)运行 隔离(主机系统上的隔离环境)并且具有有限的权限和访问权限主机系统。因此,即使该进程 运行 在容器中以 root 身份运行,它在主机系统上也不具有 root 访问权限。
但是从这篇文章:processes-in-containers-should-not-run-as-root,我看到容器进程 运行 仍然可以作为 root 访问主机系统上只能由 root 访问的主机文件.
在主机系统上:
root@srv:/root# ls -l
total 4
-rw------- 1 root root 17 Sep 26 20:29 secrets.txt
Dockerfile -
FROM debian:stretch
CMD ["cat", "/tmp/secrets.txt"]
在运行上面Dockerfile对应的镜像上,
marc@srv:~$ docker run -v /root/secrets.txt:/tmp/secrets.txt <img>
top secret stuff
如果,top secret stuff
是可读的,怎么可能。那么容器隔离的意义何在。我还缺什么,好像还缺什么。
(与我使用 docker run
的方式有关,默认情况下,所有 permissions/capabilities 都根据用户 运行 宁 docker run
命令提供给容器.
容器只有在操作员明确授予它访问权限的情况下才能访问主机文件系统。例如,在没有任何 docker run -v
选项的情况下尝试 :
docker run \
--rm \ # clean up the container when done
-u root \ # explicitly request root user
busybox \ # image to run
cat /etc/shadow # dumps the _container's_ password file
更一般地说,规则(在没有用户命名空间重新映射的本机 Linux 上)是,如果文件从主机绑定安装到容器中,则如果容器的 numeric 用户或组 ID 与文件的所有权和权限相匹配。如果一个文件在模式为0600的主机上由uid 1000拥有,则它可以被容器中的uid 0或1000读取,而不管对应的容器和主机用户名。
由此得出的结论是,任何可以 运行 任何 docker run
命令的人都可以轻松地对整个主机进行 root。
docker run \
--rm \
-u root \
-v /:/host \ # bind-mount the host filesystem into the container
busybox \
cat /host/etc/shadow # dumps the host's encrypted password file
容器中的 root 用户进一步受到 Linux 功能的限制:如果不提供额外的特殊 Docker 选项,即使 运行 以 root 用户身份,容器也无法更改文件系统挂载、修改网络配置、加载内核模块、重启主机,或者做其他一些额外特权的事情。 (而且通常在容器外做这些事情比给Docker额外的权限更好;不要随便运行容器--privileged
。)
运行 容器作为非 root 用户通常是更好的做法。用户 ID 不需要特别匹配任何用户 ID,它只需要不是 0(匹配特定主机 uid 不能跨主机移植,因此不推荐)。容器中的文件一般应该为root所有,才不会被不小心覆盖。
FROM debian
# Create the non-root user
RUN adduser --system --no-create-home nonroot
# Do the normal installation, as root
COPY ... # no --chown option
RUN ... # does not run chown either
# Specify the non-root user only for the final container
EXPOSE 12345
USER nonroot
CMD the main container command
如果容器确实需要读取或(特别是)写入主机文件,请将主机目录绑定挂载到容器中的某个数据特定目录中(不要用此挂载覆盖应用程序代码)并使用 docker run -u
选项指定容器需要的主机 uid 运行 作为。用户不需要特别存在于容器的 /etc/passwd
文件中。
docker run \
-v "$PWD:/app/data" \ # bind-mount the current directory as data
-u $(id -u) \ # specify the user ID to use
...