Docker容器的root用户

Docker 是 Linux 平台上容器的管理引擎,其提供的容器服务一方面可以很好地分配物理资源,不论是资源还是权限都能够达到隔离的效果;另一方面,Docker 的设计把更多的目光投向了「应用」本身,简化了应用从开发、测试、发布等迭代发展的生命周期。

Docker 带着「重新定义应用」的豪言,冲击着大家对软件的理解,在云计算领域更是如此。然而,新技术的诞生往往需要接受行业千锤百炼似的考验,安全无疑是业界最关心的因素之一。传统的硬件虚拟化等技术发展了数十年,逐渐步入成熟期,成为如今云计算技术的中坚技术,其高隔离性自然是保障安全的首要功臣;对于应用而言,安全问题尤为严峻,系统业务核心几乎全部通过应用来实现,应用的安全一旦失守,后果不堪设想。

正视安全,Docker 无法回避。在众多安全性考量中,有一点经常被 Docker 实践者提起,那就是 Docker 容器的 root 安全性。由于截止到目前的 docker 1.8.3 版本,Docker 依然没有完成对 Linux User Namespace 的支持,因此对于 Docker 容器而言,容器内部的 root 和宿主机上的 root 属于同一个用户,两者的 UID 均为 0。容器中的超级用户,是否会影响其他容器,乃至宿主机,自然成了大家最关心的安全问题。

Docker 容器 root 和宿主机 root

意识到 Docker 容器内的 root 用户属于超级用户之外,更多的忧虑逐渐表露,比如「使用 root 用户运行 Docker 容器内部的应用,是否安全?」,比如「容器内的 root 是否可以操纵宿主机资源?」……

如果 Docker 容器内的 root 用户和宿主机的 root 用户完全一致,那么 Docker 容器可以认为在权限方面拥有宿主机上 root 相应的权限,此时的 Docker 容器拥有超级管理员权限,原则上 Docker 容器本身完全有能力操纵宿主机的一切。然而,结果真是如此吗?

答案自然是否定的,否则的话,Docker 的安全简直不堪一击。虽然 Docker 容器内的 root 用户直接是宿主机的 root 用户,但是 Docker 可以保证两者在权限方面,拥有巨大的差异。此时,这种差异的存在完全是借助于Linux 内核的 Capabilities 机制。换言之,正是 Capabilities 在保障 Docker 容器的安全性。

Capabilities 在 Docker 容器的管理过程中使用非常方便。如果不需要授予 Docker 容器足够的系统权限,也就是足够的 Capabilities,只需在运行 Docker 容器时不使用 --privileged 参数,如:

docker run -it --priviledged=false ubuntu:14.04 /bin/bash 或者 docker run -it ubuntu:14.04 /bin/bash 如果需要授予 Docker 容器足够的管理权限,则直接将 --privileged 参数设为 true,如:

docker run -it --privileged=true ubuntu:14.04 /bin/bash 另外,在 docker run 命令中,添加 --cap-add 以及 --cap-drop 参数也完全可以更灵活的添加以及移除 Linux Capabilities。

Linux Capabilities

既然 Docker 采用了 Linux Capabilities 机制,那么何为 Linux Capabilities,我们来一探究竟。

大家一定知道,在传统的 Unix 系统中,为了实现权限的检查,操作系统上运行的进程可以分为两种:特权进程(priviledged processes) 和非特权进程(unpriviledged processes) 。其中,前者的有效用户 ID 为 0,也就是大家常说的超级用户或者 root 用户,而后者的有效用户 ID 为非 0,也常被称为普通用户。特权进程在运行时们可以绕过所有的内核权限检查,而非特权进程则必须完全接受这些检查。

虽然如此,然而实际情况要比以上的描述复杂一些。实际情况下,Linux 会将传统超级用户的特权划分为多个单位,也就是我们关心的 Capabilties。Capabilities 会有很多种,而且对于 root 用户而言,完全可以单独启用或者关闭,因此同为 root 用户,权限却因 Capabilities 的不同而存在差异。

Linux Capabilities 机制将超级用户的权限划分非常之细,所有的 Capabilities 列表有接近 40 项之多。我们可以通过几个具体的 Capability 来看看他们各自管理的权限范围。

CAP_SYS_ADMIN:CAP_SYS_ADMIN 实现一系列的系统管理权限,比如实现磁盘配额的 quotactl,实现文件系统挂载的 mount 权限;比如在 fork 子进程时,通过 clone 和 unshare 系统调用,使用 CLONE_* 的 flag 参数来为子进程创建新的 namespaces;比如实现各种特权块设备以及文件系统的 ioctl 操作等。

CAP_NET_ADMIN:CAP_NET_ADMIN 实现一系列的网络管理权限,比如网络设备的配置,IP 防火墙,IP 伪装以及统计等功能;比如路由表的修改,TOS 的配置,混杂模式的配置等。

CAP_SETUID:CAP_SETUID 有能力对进程 UID 做出任何管控。

CAP_SYS_MODULE:CAP_SYS_MODULE 帮助 root 用户加载或者卸载相应的 Linux 内核模块。