Py学习  »  docker

绝不避谈 Docker 安全

GitChat技术杂谈 • 6 年前 • 618 次点击  

本文来自作者:孙宏亮 在 GitChat 上精彩分享

文末「阅读原文」看看大家与作者交流了哪些问题?

容器技术的发展如火如荼,相关的安全技术也在不断的发展。早在容器诞生之初,行业就将其与虚拟机进行对比,其中安全的维度一直被诟病。随着容器对于软件封装优势的逐渐普及,以及安全改善的渐入佳境,这样的比较也就逐渐消散。

然而容器技术的安全问题,究竟如何?理应一个避无可避的话题。一项技术要在企业中落地,技术本身必须是安全的,同时技术的使用也必须安全。只有两者的有效结合,才能达到安全的最佳境界。

举个简单的例子,全球轰动的「GitLab误删」事件让所有的IT人员看到了,安全问题爆发带来的危害。通过该事件,也许我们并不能直接定位到某项技术的漏洞,但是流程安全以及人员的操作不规范,已然造成了非常严重的信息安全后果。

那么容器的世界当中,是否存在同样的流程安全以及操作不规范?除此之外,技术本身是否存在隐患呢?

答案是肯定的,以下我将从这两个角度来谈容器技术的安全。由于 Docker 几乎可以认为是容器技术的代表,以下绝大多数以 Docker 为典型进行分析。

安全问题的披露,一般所造成的影响都会比较大。因此,行业中多数都是浓墨描述安全问题可能造成的后果,关于如何重现或者利用安全问题的过程,一般都讳莫如深,本文有些攻击方式也将点到即止。另外,安全问题,细分的领域比较多,分析不全,还望见谅。

Docker Daemon 安全

Docker Daemon 是掌握容器命运的指挥官,那么指挥官的安全,可想而知。举一个夸张的例子,一旦虎符交出,整个军队有可能面临灭顶之灾,最后还有可能牵连国家。

大家都知道目前 Docker 抽象出了规范的 API,提供 unix socket 和 tcp 两种访问方式,我们亦可以简单地认为供本地或远程访问。存在通信,我们往往会关注通信是否认证。据笔者所知,使用 TLS 保障用户与 Docker Daemon 通信认证的依然是少数,甚至很多企业的生产环境或者容器公有云服务,也是毫不知觉。

那么,没有 TLS 的保障,会造成什么结果呢?

答案是:一!无!所!有!

首先说一个笔者自身的经历。早在2年前,容器技术刚开始走热的时候,国内诞生了一大批公有容器服务提供商。尝试体验了之后,我发现有几家在这方面根本没有意识到问题的严重性。当然,我也寻找合适机会,提醒了这些厂商。

Docker Daemon 监听了 TCP 端口并且没有TLS认证,很自然的,我们会联想到:如果外界获悉 Docker Daemon 的 IP 地址,那立即可以控制该 Docker Daemon;同时倘若不知道IP地址,该 Docker Daemon 管理的 Docker 容器也可以通过网桥间接来控制 Docker Daemon。

那么,为什么控制 Docker Daemon 就会造成一无所有呢?控制 Docker Daemon,可以增删改查所有的容器,这一点不难理解。难道除了容器,连宿主机上的内容,都无法保全吗?答案是肯定的,且看如下的分析:

  • 宿主机上的进程如何影响?通过 Docker Daemon 创建一个容器 docker run --it --pid host --ipc host ubuntu:14.04 bash,将该容器的 PID 命名空间和 IPC 命名空间都设定为Host模式,那么容器中的进程就有能力看到宿主机上的所有进程,并且还会有能力管理宿主机上的进程。

  • 宿主机上的数据如何影响?通过 Docker Daemon 创建一个容器,将宿主机的根目录挂载到容器内部 docker run -it -v /:/data ubuntu bash, 那么在容器内部完全可以查阅宿主机上的所有内容。恶意用户,可以选择窥私,可以选择窃取,同样也可以选择摧毁。

  • 原则上只要让容器中的进程拥有强大的 root 权限(拥有 Privilege 权限的 root 可以认为是强大的 root,默认创建容器内的 root 用户并不具有最为强大的权限),如 docker run --it --privileged ubuntu bash,就可以让容器内的进程肆意做与内核交互的事情,比如使用sysctl管理宿主机的操作系统配置等。

  • 除以上之外,当然还有其他方面的操作,同样会造成安全隐患,比如在容器内部关闭整台宿主机等。

以上分析并没有丝毫的危言耸听,仔细想来,一步步回溯,我们发现 Docker Daemon 的控制权几乎就代表着将宿主机的 root 权限,因此必须得慎重处理。

不过理性看来,这并不是 Docker 的漏洞,不是 Docker 的安全问题,而是属于Docker 的使用安全范畴。举个例子,就很好理解,倘若用户将 MySQL 的3306端口暴露在公网上,并没有设置 MySQL 引擎的密码,那么数据安全,管理安全均无法保障。这些道理都是一样的。读到这里,回顾下危害,也许有人就会有点不安了,如果你恰巧这方面的隐患,解决方案很重要,后续我们可以再交流。

不过,我相信依然有很多的读者,看到这会心一笑,因为他们肯定早就看到这方面的安全隐患,并且有效的通过各种方式,将其规避了。然而,我想说的是,这样做很好,但是安全无具细,后面的这些你注意到了吗?Docker Daemon 管理所有的容器,Docker Daemon 就仿佛是 SDN 中的网络控制器,很多入口从它而来,Docker Daemon 的配置安全了吗?

  • 容器间的网络访问权限?

  • 允许 Docker 修改 iptables?

  • 使用了 AUFS 存储驱动?

  • 是否设置 ulimit ? (2年前有人使用 ulimit,声称自己解决了 fork bomb,事情往往并无这么简单)

  • 是否开启 experiemental 功能?

  • ……

Docker 容器的安全

说到 Docker 容器的安全,那就不得不回到对「容器」的理解上。容器可以认为是:寄宿于操作系统的一组进程,为应用提供互相隔离的运行环境。既然是进程,我们往往会联想到进程的计算、存储、网络能力等。

说到进程的计算能力,如果对操作系统熟悉,我们很容易就想到 CPU 负责计算,而内核负责进程在 CPU 上运行的调度。进一步去了解 Docker、内核与 CPU 三者之间的关系,我们可以发现 Docker 为容器支持了很多与 CPU 相关的内核参数,比如 cpuset,cpu-period, cpu-quota 等众多参数,以满足容器的个性化需求。既然 Docker 通过内核来完成 CPU 调度,那么多个容器是否在存在内核竞争问题呢。

内核只有一个,要用内核的「容器」有多个,竞争存在吗?我们可以这么看,内核只有一个,要用内核的「进程」有多个,内核诞生至今,似乎从未有过进程竞争内核的言论。

其实,内核本身的设计就有很大一部分在服务进程,两者的关系由来已久,而且臻入佳境。出人意料的是,「容器」也就是「进程组」的概念诞生了。当前专注「容器(进程组)」与以往专注「进程」存在很大的差异,其中就有一点是「容器(进程组)」是否会竞争内核?

内核同样可以认为是一种资源,传统我们认为它掌控 CPU,内存,网络,存储等,而对于容器,它还负责管理内核范畴更多其他的资源,比如进程数、信号量、inotify(docker 1.8.0 就曾经遭受到 inotify 资源竞争的安全问题)等。一旦对其没有严加防范,竞争现象很容易被利用,换言之,资源隔离难以为继。

Fork Bomb 就是一个典型的例子。宿主机内核仅能分配指定数量的进程数,即 PID 上限比如为32768。倘若一个容器内的进程组消耗了宿主机上所有的进程,那么其他容器将不能被创建,甚至连宿主机都没有办法创建新进程,整个宿主机将陷入瘫痪状态。因此,容器世界中,一个小小的 Fork Bomb,不断地 fork 新进程,将轻松炸毁一台宿主机。

3年前,国内的容器市场中,我甚至认为 Fork Bomb 是容器公有云的头号敌人。好在 Linux 内核4.2开始支持 Pid cgroup,可以实现限制容器的进程数上限。当然如果 Linux 内核版本并没有这么高的时候,想要解决这个安全隐患难度非常大,但也不是毫无办法。

内核也是资源,竞争需防范。不过,「好戏」才刚刚开始,我们再来聊聊 Docker 容器的存储。说到存储,存储之上大家自然想到的是文件系统(filesystem)。

也许,大家听说过容器技术中有一个命名空间叫 mount 命名空间,可以实现文件系统隔离。然而,文件系统隔离,仅仅是一个非常基本的要求。上文中提到,不建议使用 aufs 做存储驱动,也与这存在一定关系。

倘若使用 aufs,创建出的容器虽然文件系统互相隔离,但是在存储空间方面却没有任何限制。换言之,一个容器如果不断写文件,将会写满存储介质,其他容器将无法执行写操作。

文件系统隔离不够充分,如果大家认同的话,也许会转向 devicemapper 等。当前 devicemapper 存有内核问题等,虽然一定程度上加大运维成本,但是是否就解决了这个问题呢?答案再一次令人失望。Docker 中的 Volume 概念,大大打破了 mount namespace。

既然命名空间被打破,存储卷空间使用量又回到以上问题,无法限制。其实文件系统只是操作系统用来管理存储的一种手段,回到设备层,文件系统对其的管理除了空间之外,很多情况下还会有 inode,那么 inode 的隔离同样需要考虑。

关于存储,进一步深入,再和大家探讨一个问题,在宿主机上什么是一个容器的存储空间?尤其在公有云环境下,原本以为容器文件系统范畴内的存储属于容器存储,对 Docker 的架构深入实践之后,发现远没有这么简单。

容器的hostname 文件,resolv.conf 文件,日志文件等都应该属于容器存储范畴,隔离的边界又一次被拉大,隐患存在的维度防御起来难度无疑又一次变大。

再谈 Docker 容器的网络,网络的可访问能力,网络的带宽控制,网络的控制流数据流分离都应该是值得规划的技术点,如若不予重视,网络有可能会成为最不省心的环节。

Docker 镜像安全

Docker 镜像承载了用户应用,甚至行业直接将镜像作为交付件。那么,镜像的安全,优先级理应放在前列。那么,就我个人经验而言,会存在哪些镜像安全问题呢?镜像本身的安全,镜像传输的安全,首当其冲。

何为镜像本身的安全,我将其限定镜像签名,镜像内容两类。镜像签名安全,大家理解起来较为简单。镜像内容,在我看来,就会复杂很多,包括:

  • 镜像基础内容。基础内容包括基础镜像,包含依赖库,操作系统发行版等,这些内容若存在漏洞,或被人植入病毒等,镜像将不会幸免。容器市场上有一些项目,专做镜像安全扫描工作,也是主要针对镜像内容,对比当前市面上的漏洞库,得出扫描结果。

  • 镜像应用内容。应用内容包括用户业务代码相关的构建内容,有无漏洞,有无被人篡改,都将影响。

  • 镜像内容性质。镜像内容存储大小,镜像内容文件个数,都会引发安全问题。比如镜像有可能因为文件个数太大,下载到本地时占用太多的inode,导致机器运行失常等。

关于镜像的传输安全,涉及的内容同样多。传输安全和镜像的组织形式,镜像仓库的安全都息息相关。我曾经在体验公有容器服务时,偶然中嗅探到了集群中的私有镜像仓库地址。

令人诧异的是,镜像仓库 registry 没有开启认证方式,因此我在容器内部可以下拉、上传任意的镜像,同样,我有能力污染所有的镜像,给所有的镜像植入病毒,这又是一起 registry 使用安全案例。

Docker 安全总结

安全是一个路漫漫其修远兮的话题,笔者不可能通过一篇短文即诠释大部分,但是笔者的态度是:面对安全,绝不避谈。本文主要介绍容器技术(以 Docker为例)的 Docker Daemon 安全,容器安全以及镜像安全的小部分,意欲抛砖引玉。后续 Docker 应用层的安全隐患,Docker 与安全技术(如 SELinux,Seccomp 等)的结合依然需要用户重视。

个人认为,Docker 的创新在于业务创新,严谨来讲并不属于技术创新。Docker 虽然诞生即将满4周年,但是在技术普及史上,毋庸置疑它目前并不算得上步入平稳期。

Docker 的确带来了很多的优势,辩证来看,缺陷同样明显,不同的场景,优劣权衡的比重并不完全一致。随着技术的发展,劣势终将逐渐被重视并解决,只是解决的方式不尽相同。

回到安全,Docker 与 Linux 的结合目前在众多场景下,都逐渐表现出一些疲态。在这里,我也一直坚信一个观点:操作系统市场依然有改进的空间,当前的形势,并不是容器技术与操作系统的最佳结合姿势。


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/YhWz54ezYb
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/2513
 
618 次点击