@gaoxiaoyunwei2017
2018-08-24T11:06:59.000000Z
字数 13436
阅读 732
黄晓轩
讲师 | 马全一
编辑 | 黄晓轩
马全一
腾讯资深产品经理,资深容器技术和DevOps专家,负责容器类产品和DevOps产品。国内早期的容器开源技术和Golang语言布道师,多次在国内外技术会议上演讲,专注于利用容器构建高效和安全的DevOps体系。
大家好,我是马全一。我现在在腾讯的SNG的腾讯云做容器还有DevOps的产品经理。因为我以前一直是做容器相关的,也是研发出身,所以我第一感觉就是容器在DevOps,尤其是在CI集成这一块是非常有前景的。包括国内最开始推广容器的时候,其实很多人都是把他放在CI的工具里面,比如做一些测试环境的集成。所以我后来在做容器产品的时候,比较关注DevOps。
在去年我偶然听到国内有一家比较知名的比特币交易所,他们在DevOps过程中,后来在审计中发现在build过程中,他们的线上服务被加壳被篡改,这个服务在线上在尝试提取比特币到一个不知名的账户上。但是被他们发现了,把这个漏洞补上了,但是从这个过程我觉得DevOps整个链条包括工具,在安全上是非常有影响的,所以后来我就在这个方面做了很多关注。之前我在华为,后来加入到腾讯云之后做腾讯云的服务。因为你线上服务,安全更是一个不可规避的问题,尤其是容器,容器在安全上一直被挑战。所以我就一直在关注这个话题。我本身不是做安全出身的,所以我只讲我在设计产品过程中遇到的这些安全的挑战,以及包括我们在日常开发过程中,用什么样的技术去把他能够尽量实现自己认为的安全。
在分享开始之前,我说一下我对DevOps的理解。我觉得DevOps只有两点:
我在这个PPT边上有一个图,这是英国的一家做Cloud Native安全相关的公司。他们2018年做了一个对DevOps的安全调查,看到海外,他们其实在DevOps安全的投入是在增加的。但是在国内好像这个话题,大家还在研究到底怎么做DevOps,DevOps安全可能还是在权限管理各方面没有做的很深。所以这次我来分享一些关于我们在做这件事情当中遇到的问题。
我会讲一下我们的方案,我们遇到的一些困境,因为是在腾讯云上提供服务,所以会有权限问题,还有供应链的问题,审计,还有你如何做安全的构建,包括使用Kubernetes过程中遇到的安全规则
腾讯云的DevOps解决方案,他的目标是要把腾讯内部好的DevOps的工具release出来,作为服务提供给所有开发者。所以我们在腾讯云产品里面重点做了编排的引擎,我们管他叫DevOps编排引擎。因为我们底层是用Kubernetes做的,所以我们把他叫做编排引擎,而没叫Pipeline,或者工作流之类的。我们因为是用容器来做,所以我们管他叫做编排引擎。
我后面会讲到很多问题,其实是因为我们这是个容器,所以他会遇到容器相关,包括Kubernetes相关的一些安全问题。但是今天我讲的并不是说Kubernetes安全的一个话题,只是大概介绍一下。
这里面我们编排引擎在上面提供有镜像扫描、构建这些能力,还有签名的工具。首先我们是提供一系列存储的机制,因为代码存储在腾讯云上我们提供的是工蜂系统,你们会用到跟腾讯内部用的一样的系统。你如果做一些编译,比如说生成一些二进制的文件,我们会有Artifact的存储。如果你用容器镜像会有Docker镜像的存储。你用的Helm Chart或者Operator,都会有特定的一些存储机制给你。
我们在这些存储里面都会有扫描,会有构建的一些在线的编辑工具。我们现在已经除了工蜂和织云以外,还集成了一些腾讯内部的研发工具。QTA是移动端的自动化测试工具,你可以用他来写一些自动化测试用例,会反馈给你一个测试报告。这主要针对移动端的功能性测试,这个QTA是SNG内部,就是在手Q还有QQ音乐都在用的产品。Wetest也是移动端测试,他比较倾向于真机测试,就是你跑在不同的机型,他会给你出一个兼容性报告,所以他会比较倾向于兼容性测试。压测大师主要是针对于你线上的服务进行压测,你的网络,你的网站能支撑多少访问,他会给你整个一套能力。织云是你作为部署来去用的,如果你线上的服务需要持续的Ops,我们整个编排引擎会调度织云来去部署,主要是这样的一个功能。
在这里面,我们重点做的就是编排的引擎,因为我们需要把所有的这些工具串起来。这是我们自己开发的,没有用Jenkins做。每次分享都会被问道为什么不用Jenkins。我们有一个同事从IEG转岗到我们部门做DevOps相关的工作,他是在IEG做DevOps的,他过来以后跟我讲,你做了这套东西,我觉得不适用,然后我们有在IEG,在游戏的业务里面,我们是怎么做的,他讲了一遍,把他的界面给我打开看了一下。
我心里感受是这样的,如果我是一个公司业务DevOps支持的一个人,我也会用Jenkins去搭建一套平台,把已有业务这些逻辑都变成很多任务让你来选,最后用Jenkins把他实现,这个完全没有问题,这就是要做的工作。但是我们在腾讯云上提供一个服务的时候,就出现一个问题,我们其实不知道你是什么样的业务,我们只能做一个通用型的。Jenkins并没有一个业务形态说你要做成什么样,他是提供一个强大的plugin生态系统给你,你可以选择。如果你看过老版的Jenkins代码,包括他那个界面,我觉得至少从我的个人感觉也是挺丑的。现在当然他演变,后来他做了一个Blue Ocean的版本,现在针对CloudNative又出了一个Jenkins X。所以他也在不停的变革,针对业务是在做,但是他之前是没有的。
对于我们来说其实遇到的问题就是,我们在腾讯云提供服务,我们不知道用户的服务形态是什么。所以我们只能提供一个相对通用型的DevOps引擎给你,帮助你做定制,然后也要提供一套生态的支持给你。
所以我们的问题就是怎么样做一个比较通用的DevOps引擎,这里有三点:通用的编排逻辑;通用的插件机制;通用的执行方式。
任何一个组件都是一个容器镜像,你甚至可以在单机上直接写一个yaml的文件来去执行。我们前面说的这个Flow,我们在界面上是用一个拖拽的方式让你创建,最终他是会映射成一个yaml的脚本,你可以自己写这样的一个yaml,所以他间接的说是可编程性的。
这个就是我们在腾讯云上做的DevOps的解决方案,然后我们把工蜂、织云等系统在往上搬。这个过程中带来第一个问题,就是帐号和权限问题。
首先在腾讯云上,他就是一个比较复杂的帐号体系。他有一种叫做开发商和协作者,还有一种叫做开发商和开发者。我去了腾讯云以后,我听了这个比较晕,不知道什么意思。他们给我解释了一下,开发商是真正有钱的那个帐号,这个帐号是你的公司主帐号,你会关联到你财务的记录,你充的钱都是在这个帐号上。干活肯定不是这个帐号,会设协作者帐号。协作者账号可以是你研发或者运维的QQ号,但是这个协作者是对应的某一个QQ号,或者某一个微信帐号。
开发商账号下的开发者没有在微信或者QQ里面有直接对应的,而是他直接创建出来的某一个帐号,是一个实体账号。这两种账号的区别就是能对应实体和不对应实体。但他总的原则就是说,任何一个帐号进来,如果不是开发商帐号的话,都需要开发商给他授权,你只有授权以后才能使用腾讯云上的各种服务,比如说像我们的容器TK1的服务,或者CIS服务,然后来去做一些事。
我们做的这个Hub账号体系,包括工蜂,我们采用的帐号体系,跟GitHub是类似的。因为我们认为这种方式,是比较倾向于互联网用户用的。首先你有用户,用户可以创建组织,用户和组织是平级的,有一个用户叫A,就不能再有一个组织叫A。在组织下你可以创建team,然后把用户加进去并赋权限。工蜂系统也是跟这个类似的。腾讯内部的很多DevOps的工具,大部分都采用这种模式,因为我们就是互联网公司,所以GitHub的这个模式比较容易接受。我们公司内部,统一登录现在都是企业微信来直接登录,所以他是两种帐号体系。
每一个我们创立的独立的服务,都要管理自己的资源,比如像我们的Tencent Hub,他管理的容器镜像。工蜂在腾讯云上,那些Git仓库是他自己来管。但是你从Hub,要部署一个服务到腾讯其他的服务上去,比如说你要去写一个对象存储,存在腾讯的对象存储上,就要查有没有这个权限。
这个里面就涉及一个问题,你怎么知道他有权限用,或者那个帐号有没有钱。Account服务用来证明谁是谁,CAM是腾讯的另一个服务,是开发商给开发者或者协作者授权使用某些服务的权限。腾讯云上的API体系是用RPC的,我们目前是RPC3.0的API。因为在腾讯开发的迭代速度比较快,所以RPC一直在改。工蜂、织云等都是其他BG的DevOps工具,他们没有投时间和精力跟着维护RPC版本的变化,而且腾讯内部产品大部分都是RESTful API,所以我们在中间做了一个账号转换系统,就是IAC(Internal Account CAM)。所有对账号的查询,权限的查询,全部用RESTful API到IAC上查询。这个服务是只在这些服务之间内部看到的,对外的用户界面上你不知道有这个东西的,所以他都到这里来查。这个是我们采用一个方式来屏蔽,这在研发里面,你发现设计模式是很普遍的。所有的业务逻辑,我们会在IAC对内部我们导上来的服务做一层屏蔽。
这个过程中我们就想什么是JWT(JSON Web Token),他是一个授权的机制。他分成三段:
我们使用JWT模式,来处理用户查询和权限查询。
比如像Tencent Hub,我们在腾讯上有个CIS服务,你可以把一个容器镜像当做一个单容器实例,一个容器镜像你可以把他看作一个网站,一个简单的虚拟机来去运行他。所以如果在Tencent Hub上去运行CIS,我要把一个镜像push到CIS服务上,让他跑起来的时候,他就要去查询这个帐号有没有CIS的权限,主服务商有没有钱做这个事。因为CIS那边还有你要跑多少CPU,跑多少内存等,一大堆的问题。这个时候Hub是不知道我当前这个用户有没有这个权限,所以他就上IAC里面前去查,我查某个用户。IAC会根据内部API调用去查他是不是能用。假设能用,他会在Http返回里面,把整个返回JWT的Token带回来,我们就会在PAYLOAD里面放一些授权的机制,这些授权机制只有腾讯内部服务再用,例如: Kubernetes的Master IP和secret key。最后调用CIS服务。这就是我们利用JWT查询在腾讯任何系统上的帐号有没有在腾讯云上被正确授权过的方式。
还有一种情况,比如说像在Hub上,我们会去克隆一个工蜂的Git仓库,拉下来做build。这个时候我们就不走这个东西。腾讯内部的产品,其实都是用OAuth做授权的,所以在Hub和工蜂之间,我们直接走OAuth授权,就不再经过腾讯云那边授权。但是查询工蜂的授权,还是会到IAC去查。所以在帐号服务的过程里面,我们主要是使用OAuth2的协议和JWT的协议来保证你是被授权过的,你有某一个使用资源的权限。这是我们在做DevOps过程中第一个问题,你有没有正确的权限体系和帐号体系。
中间这一段图,就是一个比较传统行业的Supply Chain他的供应链的变化。每个DevOps产品,他都是在做Pipeline、编排、Workflow,他其实都是在定义这样一个流程,他的期望值是让这个流程更加自动化,然后让他迭代速度更快,上线的速度更快,服务的效果更好。但是当出现这样很多环节的时候,你必然会带来很多的安全问题和挑战。所以在这里面有很多安全威胁,有四种类型比较普遍:
还有在我们开发过程中也出现了很多问题:
Google,他和IBM、RedHat、CoreOS还有一些安全的网站,他们合作在推Grafeas。
Grafeas的官方定义:“Grafeas (“scribe” in Greek) is an open-source artifact metadata API that provides a uniform way to audit and govern your software supply chain”。
他其实专门做了一个artifact metadata的一个API规范。让你来做审计。他有两种:一种叫Note;一种叫做Occurrence。Note当你定期扫整个代码仓库的时候,会告诉你有没有发现CVE漏洞。Occurrence就是描述你整个CVE漏洞具体的内容是什么。现在Grafeas是OCI下的一个项目。他的含义大致就是说叫提案,法律的解释下是提案,其实就是个规范,因为以前是没有规范的定义,这都属于标准组织,但是从OCI以后,这种规范的基金会就变多了,所以这个是一整套审计的规范。
他的审计过程是这样的。蓝色的实线就是一个DevOps流程的大多数采用的方式。我有一个code,我要做build,然后我要做镜像扫描,然后测试,然后部署,部署到不管是虚拟机也好、裸机还是容器服务也好,把他部署上去。这个过程中其实有很多审计的结构产生,他是按照metadata产生,在这个链条里面比较普遍关注的是:
所以他会产生这样一个链条的传递。然后当你事后再审计的时候,你会发现我从code一直到扫描,所有过程中我所使用的这些都是具有一致性,不会在中间过程被篡改。就像我前面讲的那个例子,如果你在build过程中被加壳了,那你SHA256的包肯定要改。如果你有这样整个审计机制,你很容易发现问题,这就是Grafeas一个比较应用的实例。
在Kubernetes,有一个叫Kritis这样一个Admission Controller,来实现Grafeas在Kubernetes里面的管理实现。所以Grafeas整套来实现一个供应链的管理,重要的一点就是说,你要能够有一个审计的原则,然后你要能够知道你整个链条里面,从开始到最终部署的是一致的,不要在过程中被篡改,这个是我们在做这个产品的过程中遇到的另一个安全的挑战。
因为我们提供了容器镜像和二进制文件build功能,所以我们要有一个安全的build环境给你。
现在你做一个Docker镜像build的安全问题,大多数来源于你要以Root权限来去执行Docker Daemon,然后靠Docker Daemon的API执行Docker build。这个时候你这个root权限其实已经映射到你容器里面。就算你把这个权限变小,他里面其实还是root权限,他会引发有很多安全问题。
解决的方式:
不以root权限做build。Google发布了一个工具Kaniko,就是不以root权限做dockerfile的build。还有一个RedHat有一个叫Buildah的项目,他是不同的实验方式,但是也是不以root权限来做build。
在腾讯云上,我们其实就更简单粗暴一点,我们直接用了Kata。Kata是挂在OpenStack基金会下面,他跟整个容器的不同情况,就是说现在在左侧的这边,比如我们在腾讯云上买一个Kubernetes服务,就是左侧的情况。我们反正认为你用的虚拟机都是你的,所以这些容器之间也都是共享kernel的,即使出问题也是在小范围内,不会影响到其他人。
在做Docker Hub服务的时候,他的多租户的形态,我们就不能这么干了。我们用Kata这种形式,我虽然在Kubernetes去跑,但是你每个Virtual Machine里面还是有一个隔离的,每一个容器跟容器之间是有自己的kernel,他相当于是一个KVM裁剪版。我们就在Kata Container里面使用Docker in Docker这个方式去做build。就是说Kata Container里面先跑一个容器镜像,这个容器镜像里面跑了一个Docker Daemon,我们再把build任务下给Docker Daemon。所以他整个是在一个相对比较封闭的,达到KVM隔离机制的虚拟机环境下做build。当然我们也在研究Google和RedHat的产品怎么做的。但是我们觉得这种方式来的更快,更简单粗暴一些,所以我们现在在腾讯云上是这样做的。
我们再讲镜像扫描,这个是DevOps里面用容器去做DevOps普遍采用的流程,就是说我去做完build以后,我肯定做一个Image Scanner。在上生产环境以后,要有一个事后的审计。
我们先说CoreOS Clair,这是专门做容器镜像静态扫描的,会告诉你CVE漏洞是什么。腾讯云上的产品也是用Clair做的。你每次push一个镜像上来,我们都会去扫,看看有没有漏洞,有漏洞的话,直接通知你是哪个CVE的版本有漏洞。
这是Docker企业级解决方案Nautilus。他跟Clair基本上是一样的。所以我们反过来讲,他到底怎么扫的?我们都知道把容器发给他,把版本发给他以后他就扫了。后来我稍微研究了一下,这个事是这样的,首先这个CVE漏洞上有一个编号,他影响到的linux版本,他相关的,比如这个图写的是openssl,后面有Heartbleed漏洞,他怎么扫呢?当你一个容器镜像上来有很多层,拿到这个层以后,因为他是tar包的格式,我就把tar包解开,每个容器镜像都有manifest文件,我同时会去扫,我会生成manifesical,其实就是描述了这一层容器镜像里面是什么?有的容器镜像你就能够Scan出来说他装的是openssl,所以采用这种方式把每一层镜像你传上来的去扫。当然我扫过来的镜像都是有哈希值的,每个哈希值我扫过的,有哈希值的我就不扫。CVE的format上会写是哪个系统版本,哪个软件,哪个版本有什么什么样的漏洞?把我扫到的结果去一一对比,形成整个CVE的报告。
所以这个模式并不是针对容器经常做的,你看到很多像产品的扫描其实都是采用这种模式来做的。所以你在市面上看到的都是静态扫描,就是说我只能对你这个软件没有运行的静态情况去做扫描,而不是我运行起来再做内存分析,这种扫描其实很少。这个就是静态扫描的功能。
然后我们再讲,我们如何构建一个运行环境?安全的运行环境,因为容器镜像是轻量级的隔离,今年在哥本哈根的一个会上,Google发起的一个gVisor项目。他就是运行了一个轻量级的沙箱。右边的图就是怎么做的。Daemon去调Containerd,Containerd再去调runc去创建。gVisor就是实现了一个新的runc叫runsc,会劫持所有在Container里面的内核调用的api,做一次虚拟的kernel。这本版本还比较初期,实现api数量比较有限。还有各种各样的问题,但是这表明了这样一个方式,他是说我从下往上把kernel的api重新实现做一个更轻量级的沙箱。因为有些api在业务层面确实是没必要调用的。
还有一种,就是我们刚才讲的Kata,Kata是从上往下,让他变成一个非常轻量级容器的沙箱,所以这是两中方式来构建一个安全的引擎。
怎么做呢?昨天我不知道孙辰星有没有讲,在(英)里面我们跟大家合作,在一个kubernetes集群里面,可以在不同的node节点部署不同的runtime。比如在一个节点用docker daemon,在一个节点用gVisor,另一个节点用Kata,我们给他设不同的label,所以当我们要执行一个build任务的时候,我们就直接告诉他这个任务是下给Kata的node节点的,所以他通过kubernetes的selector机制下到Kata那边。如果我们认为这个任务不需要那么安全级别那么高的,他就会下给docker daemon的节点。他采用kubernetes混部不同runtime方式来实现一个隔离的机制。这就是我们希望为DevOps过程中,根据你业务的情况,提供不同级别runtime。
我最后就讲我们在Kubernetes安全策略做了很多,这是他的一个模型,我有一个LB,进来跑不同的pod里面去访问,在这里面有很多很多安全的点,需要大家在使用DevOps过程中做的。
1、你的运维、研发操作的时候必须首先要用TLS,就是你的那个Master的那个点,必须要Https的。
2、你要有RBAC的授权,就是说对不同的操作者来操作这个集群的时候,给他不同的权限。
3、你可能实现自己的Admission Controller。刚才我们前面讲的日志审计,其实也是用这个来做的,这是你需要使用一些自定义。然后就是在note节点和Master节点之间,一定要使用这个证书。这个证书是这样,在安装集群的时候,会有一个根证书,你会先生成一个根证书,然后再往下签发,比如Master证书等等,所以你要有一套证书的机制,包括安全保存证书的机制来去做,保证Node节点和API节点之间是可授信的访问。
4、Network Policy。是限制pod和pod之间访问的,实现网络上的隔离。
5. Pod Security Policy。你pod节点是以什么权限运行的。
整个kubernetes在DevOps流程的任务执行过程中,我们也要设定这些Policy来保证隔离性和可用性。即便是这样,其实还是有很多问题需要我们去解决。所以这个就是我们在最底层,Kubernetes在DevOps执行任务平台上我们做了很多安全的增强。
这个就是我整个的演讲,我们设计了这样一个通用化的引擎,用容器的方式去运行DevOps,这个过程中我们设置了很多保证他的运行安全,有日志的审计,帐号权限的管理,最终在底层运行平台做了一些加强,给大家提供更安全的保证,这个是我在过程中遇到的整个安全挑战。