社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  docker

绝不避谈 Docker 安全

GitChat技术杂谈 • 8 年前 • 736 次点击  

本文来自作者:孙宏亮 在 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
 
736 次点击