数万台服务器下的Docker深度安全实践

javascript/jquery

浏览数:157

2020-7-5

本文整理自OPPO互联网安全团队刘湛卢的分享,他们主要负责OPPO互联网安全团队的研发工作,如果你也关注容器安全问题,希望这篇文章能带来启发。

同时欢迎关注OPPO互联网技术团队的公众号:OPPO_tech,与你分享OPPO前沿互联网技术及活动。

本文主要内容如下:

  1. Docker生态与架构
  2. 安全问题和应对方案
  3. OPPO容器安全实践
  4. 容器生态的安全展望

先简单介绍一下行业背景。

当前,OPPO在全球有超过2亿+的DMU,最近几年数据量增长超过180倍。从服务器数量和业务量的变化趋势,可以看到互联网业务整体的发展趋势是呈指数型上升,同时业务量的增长带来了服务器数量的高速增长,这也与业务指数曲线是类似的。而当下,业界主流技术已经从物理服务器承载业务转向了Docker化,Docker是当前热门的云计算主流技术。

Datadog 2018年6月统计的数据显示,25%的公司已经采用Docker,预计2020年会达到50%,其他没有使用Docker的公司也在追赶过程中。

一、Docker生态与架构

所谓容器生态,就是围绕容器周边的一系列元素和容器一起构成整个容器构建、运行的方案和工具、文件等,而容器的安全并不仅仅只是容器本身的安全性,也和容器生态的安全紧紧结合在一起,需要有容器整个生态的安全支撑才能一起构建容器完善的安全方案。

那么容器的安全具体包括哪些元素?毫无疑问,Docker本身是其中核心的一部分。这是把容器运行起来的关键,控制着容器的启停、管理容器运行所需要的资源、以及容器和外界的交互等容器核心功能点。

同时,Docker容器的运行是需要镜像作为支撑点的。每个业务功能可能会有一个镜像,当业务众多,而且有不同版本时,尤其像微服务这种对业务的拆分粒度很小的情况,会产生大量的镜像。在Docker里面是由registry来管理镜像,他存放着我们所有的镜像,当Docker在运行的时候,可以指定从某个registry拉取相应镜像到本地运行,当然这个拉取动作Docker自己会去执行。

到了生产环境,尤其是业务体量比较大的公司或者机构,对如何管理镜像的分发、容器的调度、业务的高可用能力、容器多副本的维护等方面提出了很大的挑战,由此kubernetes应运而生。kubernetes的出现更加方便了容器在大规模使用,复杂业务场景上的使用。

先来看一副Docker安全与传统安全的对比图:

传统的主机层安全问题包括操作系统的安全漏洞,webshell,恶意二进制程序,rootkit,内核安全,ssh暴力破解等。

Docker的安全包括:Docker本身的安全(包括主机的安全),镜像的安全,registry的安全,镜像分发传输的安全,编排系统(kubernetes)的安全将会成为容器安全建设的核心点。

Docker的架构:

一般而言,Docker会跨私有网络和互联网运行,宿主机,企业级自己的私有注册中心都会在私有网络中,而Docker hub 这类公有注册中心,互联网上的其他的公共注册中心会运行在公网。在私有网络中,宿主机上包括Docker客户端和Docker的守护程序(Docker daemon),通过Docker客户端向Docker的守护进程发送Docker指令来启停容器,或者获取容器的相关信息。Docker守护程序则接收到来自客户端的请求则执行Docker命令,包括解析Docker指令,执行容器的启停,向各个仓库拉取镜像等来完成容器的操控。所以Docker守护程序的安全是非常关键的,他能直接操控该主机上的所有容器。

二、安全问题和应对方案

几个核心安全问题,第一是主机与容器守护安全,第二是镜像安全,第三是容器运行时安全问题,第四是生态安全。

主机与容器守护安全问题。主机上的安全配置是否影响到容器的运行,主机的安全漏洞是否影响到容器运行,容器内的进程是否可以利用主机上的安全漏洞。

镜像安全方面。镜像是否安全,镜像传输过程中是否会篡改,镜像被销毁后是否还存在安全问题。

容器运行时的安全问题。各容器之间的通讯是否安全,隔离是否充分,容器在资源使用上是否安全。

生态安全。主要是Docker本身的安全性,还有编排系统的安全问题,容器的秘钥管理和传统的秘钥管理是否不一样,容器化以后的数据隐私保护方案是否和传统方案一致。

2.1 主机与Docker守护进程的安全问题


先看Docker守护进程的安全,这个是用root权限创建的文件,通过非root文件就把它删除掉了,这种主要是Linux对内核隔离性的不足,在Docker使用时隔离级别是由用户自行决定的,把这个账号直接加到Docker的账号组里就具备了这个权限。

我们再看一个例子,曾经爆出来的Docker swarm集群管理配置问题,就是将Docker daemon的相关接口暴露在公网上,并且并没有启用任何保护措施,从而导致任何人都可以使用Docker api来操纵容器,这就造成了一个危险极大的安全隐患。

而通常安全可靠的做法可以由这几种方式:

  1. 使用Docker本身提供的TLS/HTTPS加密接口通道,但这种在大规模使用的时候在证书和秘钥的管理方面会带来一定的挑战。
  2. 通过统一的代理来访问每个Docker daemon的接口,而不直接暴露其接口,这样使用安全代理加固的方式保护Docker daemon的接口安全性。

总的来说 Docker 守护进程的安全问题主要来自这几个方面:

  1. 需要root权限运行,这个在daemon安全上可能会带来很大的安风险;
  2. 守护进程对外提供API服务,用于的容器和整个Docker的管理工作,这使得对这些接口进行安全保护是非常重要的;

应对方案:

  1. 尽量不要直接开启Docker remote api服务,如果必要则可以通过中间代理层来做隔离控制;
  2. 在隔离层添加ACL,添加控制白名单,加强对访问源的监管;
  3. 启用TLS认证,加强验证和通讯的传输过程;
  4. 守护进程的相关安全配置的合规扫描和审计;

2.2 镜像安全问题

所有容器都是基于镜像运行,如果镜像的安全性受到威胁,显然容器就被攻陷了,甚至主机都可能沦陷。

Docker hub是在行业主流的镜像仓库,其由Docker官方提供。曾经有人对其镜像进行抽样,使用clair对镜像扫描,发现安全的镜像只有24%,而风险镜像占到76%,其中高风险的镜像有67%,这说明镜像已经成为Docker安全中的一个重要的安全攻击防御战场了。

例子:有人曾经利用Docker hub 传播了17个恶意镜像,其中包括有挖矿代码,后来分析其相关镜像的恶意代码,发现其中相关联的钱包地址显示,这些恶意镜像挖出了价值9万美元的门罗币;所以,利用恶意镜像进行挖矿、传播恶意文件、勒索病毒、逃逸到主机系统做恶意攻击等等,这些都可以植入到镜像中。

总结一下镜像会产生安全问题的几个方面:

镜像内容安全:镜像可以携带的安全问题如依赖库漏洞,植入病毒,恶意文件等其他安全问题,如果使用了基础镜像,那么基础镜像是要可信的;

镜像内容性质:镜像内容的大小,在磁盘上是否会创建或者包含较大的磁盘空间,因为一个镜像可以创建多个容器,容器多了以后容易导致主机资源不够用,再者是镜像中文件个数过多,会导致大量的inode被占用而过多消耗系统资源;

镜像仓库安全:包括仓库本身的问题和安全加固,镜像的传输安全,安全认证,镜像签名体系等等;

镜像中的用户权限控制:默认在镜像中的进程是root权限运行,用户可以在构建镜像时遵从相关规范,以最小权限原则执行;

镜像扫描审计:通过对镜像的深度扫描和审计,可以及时发现镜像的安全问题。

镜像安全扫描工具:

Clair:当下非常主流的镜像安全扫描工具,其扫描分析特点是使用静态分析方式,会把镜像包拆开,对镜像进行层级分析,和已知的CVE库进行版本对比的方式来扫描镜像。这种分析方式有很多局限性,只能根据CVE库的版本进行对比,换言之对0day是毫无防御能力,没有收录在CVE或其恶意库中的将得不到准确的扫描结果。所以扫描效果不是特别明显。

其他几个扫描工具包括 anchore 和 Dockerscan 的扫描工具也是类似的思路。

这些都是当前开源、主流的一些扫描工具,后面我们也会讲讲oppo的深度镜像扫描系统的相关实践。

2.3 运行时安全问题

容器运行时安全是从Docker daemon根据镜像拉起一个容器开始,那么在运行过程当中,容器的安全性就和容器的运行机制、运行时库、系统调用、读写行为等这一系列的动态动作关联起来了。前不久爆发的runC容器逃逸的漏洞,简单来说这个漏洞就是通过在拉起一个恶意镜像的过程中,把Docker-runc这个关键程序覆盖了,当然Docker daemon下次再启动容器时就会执行替换的Docker-runc恶意代码。除了runc容器逃逸的安全问题,主机层内核如果存在dirty cow漏洞也可以溢出到主机上。

容器运行时安全,除了从容器内逃逸到主机上之外还有其他的方式,容器运行时的安全问题还有下面这些:

  • 磁盘资源限制上,例如某个容器把磁盘写满了导致其他容器无法正常工作。
  • 容器之间的Ddos攻击,某个容器把当前主机的带宽打满,导致其他容器无法工作。
  • 由于kernel层的隔离性不足上面,例如/proc,/sys等子系统的隔离性不足,容器内看到的cpu个数/mem等数据不准确等等。

那么应对这些问题都有哪些办法?Docker本身在这个层面上的安全控制能力是比较弱的,主要依靠内核层面有提供一些能力和权限限制工具来辅助处理,包括seccomp,capability,selinux,apparmor,tc流量控制,quota技术等。

2.4 容器生态安全问题

除了容器的运行时安全,镜像安全,守护进程的安全问题,容器生态中还有非常重要的一环,容器编排和调度,当下最主流的容器编排和调度系统kubernetes,那么kubernetes的安全性是怎么样的呢,其实kubernetes也发生过好多安全问题,包括曾经遭遇的大范围的劫持等。

对于kubernetes的安全应对方案:

  • 对系统使用最小特权。
  • 定期更新系统软件来确保已经被官方修复的漏洞得到保护。
  • 对其操作日志进行记录和审计,是系统保持在一个被安全监控的环境下运行。
  • 权衡好安全和生产力的依托关系,通过调整产品形态把对一下有安全风险的功能关闭,或者使用其它方式替代使用。
  • 使用安全端口进行通信等。

3. OPPO容器安全实践

整个容器的生命周期,包括了从镜像构建到编排分发,从容器创建到运行、销毁这一系列阶段,因此我们需要从容器生命周期全阶段进行安全加固和保护。

在镜像的生成阶段:从镜像构建到把镜像推送到注册服务器,镜像构建中需要根据业务情况来定制安全构建策略,遵从镜像的安全构建规范,例如创建专门用在容器的用户来启动容器内业务进程、使用可信镜像、涉密信息不存储在Dockerfile、在Dockerfile中使用copy而不是add等等;那么在注册服务器,镜像仓库中会进行镜像的深度扫描、签名验证等以防止恶意镜像流入生产环境的镜像仓库,同时需要对镜像仓库接口进行加固和镜像操作日志进行审计以防止镜像仓库系统的入侵攻击和被恶意修改。

编排分发阶段:编排系统同样需要做安全基线审查扫描,提供有效的安全策略配置,编排系统kubernetes的接口层安全加固,这是由kubenetes本身所提供的一系列机制来实现集群安全控制,其中包括API Server的认证授权、准入控制机制以及保护敏感信息的securet机制等。同时在编排系统也需要做好日志审计,以便于风险问题的预警分析和溯源。

容器镜像的传输:在传输途径中需要使用https进行加密传输,以防止中间人攻击篡改镜像。

镜像的运行:镜像最终是需要流转到主机来真正使用,由Docker守护程序根据镜像创建容器运行,那么在主机层的镜像审计和回扫都是很关键的,同时也需要对镜像进行深度分析、镜像的合规基线扫描,来检测在主机侧是否有恶意镜像。

3.1 镜像安全构建

安全构建,是在业务侧进行,我们需要给业务侧提供镜像的安全构建规范,业务方严格强流程按照安全构建规范完成构建。

主要是为了达到以下几个目的:

  1. 有可信的安全的基础镜像,可以由运维或者基础镜像团队统一提供安全基础镜像;
  2. 镜像内业务权限最小化,依赖资源最小化,例如使用专用的容器运行账号来启动业务进程而非root用户,移除不必要的权限如setuid/setgid等系统调用能力防止提权攻击;
  3. 尽量减少镜像中外部资源的使用;包括使用COPY替代ADD,因为ADD可以通过外部链接来加载资源,不在Dockerfile中单独使用更新命令等等。

3.2 镜像仓库加固

镜像仓库的架构中,一般仓库API不要直接对外提供服务,可以通过增加一个中间代理层proxy来负责所有访问对接,不论是在开发环境构建镜像还是扫描引擎对镜像进行安全扫描,还是产环境对容器进行编排部署都通过proxy进行来做镜像的操作审计,客户端认证、授权等操作。

中间层的作用主要包括:

  • 镜像的提交审计;
  • 传输加密;
  • 客户端认证、授权;
  • 扫描引擎和镜像仓库的扫描对接;
  • 对镜像仓库服务器IP做访问控制,接口恶意调用拦截等安全加固。

镜像仓库上可以给它进行角色上的权限认证,比如不同角色分配不同权限,像开发、扫描和生产环境上分别配置不同的角色和配置不同权限,对业务进行划分,不同业务使用时也有不同的权限,可以设置黑白名单进行访问控制,日志操作审计,在操纵流程中包括上传、下载及所有操作。

3.3 镜像深度扫描

把镜像从镜像仓库拉取下来,对镜像的Dockerfile做指令分析,当然镜像里面并没有直接携带Dockerfile文件,而是对其产生的history指令进行分析扫描,检测其是否有不合规指令,包括基础镜像进行分析,账号权限分析,ADD指令分析,内容信任分析,setuid/setgid等合规检查。

镜像是由各个层叠加而成,在history指令分析以后,我们需要对其各个层进行拆解,对每一个层级进行深度扫描分析;拆解以后,会对所有文件进行恶意特征扫描,包括从公司内部收集和沉淀的恶意版本特征库,cve漏洞库,黑白名单等进行版本特征扫描。

在版本特征扫描之后,会进入到深度扫描部分,包括webshell的深度扫描,例如使用yara规则,语法分析,大数据机器学习,模糊hash检测等;恶意elf文件的深度扫描,同样的,elf的扫描也有相应的yara规则,黑白名单,符号表分析,模糊hash,病毒、木马特征库检测;敏感信息检测,分析镜像各层中的文件,查看里面是否存在敏感信息,比如说是镜像里面写的有各类账号密码(如mysql/redis),我们会对其进行统一分析扫描,用于保护密码泄露,及早发现和预警。现在各类敏感信息泄露的事件层出不穷,敏感信息泄露也是我们非常关注的一个层面。这个就是整体的深度镜像扫描流程。

刚才我们介绍的是单个镜像的扫描全流程,整个镜像仓库应该如何去扫描?OPPO当前的用户体量也是非常庞大,有超过两亿+的用户,业务体系也非常庞大,像浏览器,信息流,内容分发等互联网业务非常丰富,现在微服务的架构大行其道,成千上万的镜像该如何组织,如何扫描,这是非常值得我们深度思考的问题,从镜像构建到镜像管理都是非常具有挑战性的。

从实践来看,镜像的组织一般划分三大层次:

  1. 由运维提供的基础镜像层,该层镜像只提供系统基础能力,必要的通用工具,运行时库;
  2. 基础组件层,基础组件层会对各业务提供基础组件,包括相关的业务通用库文件等等,提供相关共性业务所需要的通用能力;
  3. 业务服务层,这个层面的镜像是完全业务化的,不同的业务有不同的镜像,一个业务有多个镜像;
  4. 并且这个三个层次一般都有继承关系,基础组件层会继承自运维提供的base镜像,业务会继承基础镜像。

3.4 主机安全加固

除了镜像的安全扫描,主机层也需要对Docker进行安全加固,包括两个层面:

  1. 内核层面的加固:使用apparmor/selinux等配置精细的安全策略,针对进程级的通讯访问权限做限制,seccomp:(secure computing mode),是一种内核特性,可用于限制进程能够调用的系统调用范围,从而减少内核的攻击面,用于构建沙箱;capability,用户权限的能力限制,把相同的用户划分为不同的各个组,可以给每个组赋予的系统调用能力不一样,例如系统超级权限用户root,可以把它划分成多个组,每个组给做一些不同的能力削减,同样是root用户所能操作的能力是不一样的,从而达到权限的精细化管理。
  2. 用户层加固:尽可能的缩小容器用户的权限,限制挂载敏感目录,磁盘单独分区用于运行容器,主机安全的基线配置规范,Docker守护进程的日志和相关配置目录进行操作审计等这些层面来加强对主机的安全加固。

3.5 容器日志收集

主机日志审计,需要有一套高效日志收集系统,统一日志规范,在主机上有统一的日志收集容器,不同的业务容器的日志统一收集发送到大数据平台,进行恶意日志分析,包括使用日志规则库进行恶意日志扫描,对恶意样本日志进行训练,使用机器学习方式做补充识别等业界主流日志分析方式。分析到异常日志对接到统一的安全预警平台进行容器安全预警。

3.6 流量分析

网络流量安全:Docker daemon会帮容器在主机上建立一个网桥Docker0用于容器间的通讯,因此我们在主机上做流量分析时需要同时监听Docker0和eth0(当然这里的名字需要根据具体的主机配置来定)确保同主机和跨主机的各容器之间的流量都能被分析到;流量分析还有一种方式,交换机旁路镜像分析,这种方式的优点是不影响主机的计算力,可以分析到容器跨主机之间的通讯,但是不能分析同主机的容器流量,也无法检测和防御同主机的容器之间Ddos攻击。

流量分析主要是检测容器间的恶意访问,包括恶意域名检测,网址检测,入侵检测,病毒检测,内容审计等,同时会做到协议还原,文件内容还原等,包括像主流的协议,TCP/UDP/DNS/HTTP/MYSQL/REDIS等等。同时在网络层进行网络安全配置规范化,例如只映射必要端口到主机,特权端口禁止映射,不共享主机网络的namespace等。在主机上做TC,traffic control,防止容器间的Ddos行为;

3.7 对容器进程的监控

  1. 获取容器的进程列表,把容器ID和其相关进程映射起来;
  2. 在主机层监控异常进程,发现有异常进程,例如容器中的反弹shell,确定其所属容器并预警;
  3. 对敏感目录的挂载进行文件监控,发现有异常操作进行预警。

除了做进程监控外,进程的审计调用也非常关键,包括网络是否有外联网络联到恶意的地址或域名,Exec函数族审计,还有域名解析审计。Docker的关键命令程序进行监控,需要监控Docker目录下像Docker-runc、Dockerd、Docker的程序有没有被篡改,需要进行监控和预警保护。

3.8 主机入侵检测与Docker的结合

主机入侵检测中,首先需要把进程和容器ID、镜像ID都关联起来,对进程和相关的webshell/恶意二进制文件进行疑似恶意分析,对于疑似的恶意文件提交到后台进行yara,符号表,特征库,ssdeep的模糊hash等方面的深度分析从而形成检测结果。在这过程中也会遇到比较大的挑战,例如webshell扫描,扫描过程中容器启停问题,业务混布,文件多而且混杂,在基线扫描方面也需要考虑的针对容器自身的安全基线和安全策略的扫描。

这是oppo在入侵检测方面覆盖到Docker的检测实践:第一个是检测到容器中的一个反弹shell的问题;第二个是容器外部挂载的一个目录中发现了webhsell;第三个则是在容器运行中发现的一个恶意二进制的后门。

4. 容器生态的安全展望

总体来说容器的安全方面包括:

  1. 容器的安全运维方案:自动编排,编排系统的安全性,对接到现有业务中,为了兼容业务架构,在容器上线的初期有可能会做出调整而破坏一部分安全机制;
  2. Docker方案代替传统方案之后对数据的安全审计和秘钥管理也会带来很大的挑战,像容器的漂移性,部分流量并不会过交换机,所以其安全审计方案会变得更加复杂;
  3. 容器自身的安全机制,包括0day,而且目前容器主要还是依靠主机来提供安全机制,而Docker本身对安全方面所做的较少;
  4. 对内核的安全机制依赖,目前内核的隔离机制尚不完善,同时内核的安全问题也透露到容器层面;
  5. 防御与检测方面:容器漂移非常频繁,同时与主机上文件的映射关系较复杂等等,这一些列问题都会给让与检测的带来很大的挑战,而且方案也会更加复杂。

最后重点来啦:

OPPO互联网运维云存储团队急招多个岗位,欢迎对MongoDB内核源码、Wiredtiger存储引擎、RocksDB存储引擎、数据库机房多活、数据链路同步系统、中间件、数据库等有兴趣的同学加入,一起参与OPPO百万级高并发文档数据库研发。

工作地点:深圳 / 成都

联系邮箱:yangyazhou@oppo.com(最好注明来源思否)

作者:OPPO互联网技术