Unikernel ,是最近被吹嘘过头的技术,声称拥有一系列特性,从而成为“更好的问题解决方案”。最常说的特性是它们“更加安全”。本文是系列文章的第一篇,来仔细介绍unikernel的实际情况,这样大家能够正确地认识它,在它们擅长的场景下使用它们,并且避免被忽悠。
总的来说:使用unikernel的话,你的应用会运行在和kernel(ring 0)一样的空间里。任何缓存溢出都意味着暴露了系统的远程访问,并且可能造成灾难性结果。
首先,我认为unikernel有其适用场景。比如构建嵌入式系统时,实际上这也是最初该技术出现的原因。问题是现在大家开始希望unikernel演变为另外一个东西:更好的hypervisor或者更好的应用容器。之所以认为unikernel“更好”的原因之一是传说中的安全优势。
安全是一个复杂的话题。任何在linux空间里工作了很长时间的人都已经厌倦了这个话题。尚未在信息安全(INFOSEC)空间投入大量时间的人会觉得困惑,因为他们认为安全是单独的一块,但是,在所有的IT原则里,安全极其依赖于 系统思维 。
他们认为unikernel更为安全是基于一个维度:代码更少,因此“攻击面”更小。字面上看,这样让系统更加安全,因为受攻击的软件更少。但是实际上,unikernel的架构总体上可能会让系统更不安全。
攻击面 是一个安全术语,是所有“攻击向量”的总和,或者是可能针对某个特定系统的“攻击通道”。因此,如果你有一个面向互联网的web服务器,并且提供HTTP/HTTPS的接入,这就是攻击面,或者可攻击系统范围的一部分。类似地,操作系统(OS)以及加载到服务器上的任意软件都可以认为是系统攻击面的一部分,因为如果攻击者得到OS的访问权限,他们可以攻击所有其上的软件,试图 升级特权 ,或者进一步入侵系统。
最为极端的情况下,从攻击者的角度而言,系统的攻击面可以认为是整个系统本身,这实际上使得这个名词没什么意义了。相反,大多数安全工程师会围绕系统构建“风险模型”,评估入口点(攻击向量),攻击者类型,攻击者方式等等。这样的风险模型有效地反映了系统高效实际的攻击面。
理解这些的重要一点是攻击面是可以被攻击的方面以及可能攻击结果的全局度量,意味着系统入侵可以深入到什么程度。通过互联网访问web服务器的日志文件和远程root控制的危害性不可同日而语,后者得到了单个服务器的完整权限,并且攻击者可以使用该系统进一步入侵整个系统。
也就是说,攻击面不仅仅可以通过有多少攻击向量来衡量,而且可以通过可能的攻击结果来衡量。也就是说,任何特定的攻击向量必须考虑到攻击者可以通过其所达到的入侵级别。因此,攻击向量的升级是和入侵深度相关联的。如下是一个简化的例子:
在你认为“相对面”数量下降的地方,我认为虽然web服务器日志的泄露是一个问题(这个是基线的话),但是远程用户访问这个问题更严重(如果执行威胁模型这个是几倍于基线)。同时,完整的管理访问是大多数攻击的根本原因。
这就让我们开始思考这个问题:unikernel实际上可能并没有传统普遍意义的操作系统安全,因为任何入侵都是A)远程和B)拥有管理权限的(最差情况中的最差情况)。
这样,unikernel增大了攻击面。移除软件并且在最小化系统上运行并没有什么特别的。我们已经这么做很多年,将其作为一种标准的加强技术,并且该技术可以应用于hypervisor,容器,甚至纯物理硬件。
这是怎么回事呢?接下来详述。
不幸的是,unikernel的核心前提是将kernel,操作系统以及应用程序扁平化到一个单一实体里。它实际上是自定义kernel,将应用程序集成为kernel本身的一部分。为你的软件创建出刚刚好需要的kernel,来提供对硬件组件(磁盘,网络,RAM,CPU)的访问。这些全都使得系统更不安全了,即使攻击面比以前小。
很久以来,传统操作系统都是使用保护ring来允许系统访问级别的升级。Ring 0是kernel运行的级别。设备驱动运行在ring1和ring2上,应用程序或者“用户空间”运行在ring3上。这些保护ring让某个应用程序无法读到其他应用程序的内存。正是这样的机制阻止了的简单的远程访问入侵,比如针对web服务器的缓存泄露无法访问到内存的其他部分(web服务器应用程序之外的内存)。
那么这里有个问题,攻击者必须找到应用程序代码的“0-day”入侵,来得到基于unikernel系统的完整访问。应用程序运行在ring0,因此任何缓存泄露都能得到系统的远程访问,并且能够在服务器上运行任意代码,这为攻击者提供了针对整个系统发动攻击的基点。
想想这很难或者不可能吗?攻击者没有应用程序代码?不知道在哪里发起攻击?不,他们知道。
黑客们都相当有经验,并且访问应用程序代码并不重要。在BlackHat/DefCon的演讲中,Michael Lynn演示了针对Cisco路由的完整远程攻击。这对于有经验的黑客和研究人员来说就是小菜一碟。
所以,现在你已经了解了unikernel是怎么增加系统的攻击面的吧,因为所有东西都以已经授权用户的名义运行着。你故意移除了所有Linux/Windows上已经存在的相对复杂的安全机制,还没考虑那些可以从默认OS安装上添加的所有额外的安全机制,这些机制可以加强安全,并且让很难以不可控的方式升级权限。
并且当你在做这一切的时候,你还相信着这样的谎言“unikernel更安全”。
想以安全的方式降低应用程序的攻击面?在容器里以非特权用户运行。
在容器内,只运行应用程序所需要的静态连接的库(比如,libc)。以这种方式构建的容器从几百k到几十兆(和unikernel系统几乎一样小)。当然,运行容器的主机还有更多软件,但是黑客并没有这些软件的直接访问权限。黑客必须入侵进应用程序,然后才能攻击宿主操作系统。另外,因为这是通常意义的Linux操作系统,很多安全机制(SELinux, Tripwire)能够在宿主级别运行,让应用在容器内隔离运行,并且检测到未授权的运行着的应用程序的变动。
太好了!攻击面减少,并且提供了unikernerl假装能提供的功能。
unikernel要想重建通常意义的操作系统所能提供的大量内建的安全机制,还有很长的路要走。这些操作系统内在包含:
unikernel这些都没有,并且实际上,因为其架构,还不清楚这些级别的安全保护是否能够适用。因此,你可能会问,我们为什么要花费资源来解决unikernel的安全问题呢,特别是该技术的其他优势已经在更为可靠的计算模型里也实现了。
在你加入unikernel阵营之前,要仔细考虑下unikernel的核心优势——更加安全——可能从根本上就是错误的并且误导人的。unikernel很可能比通常意义下正确配置的OS更不安全,并且比正确配置的基于VM或者容器的方案不安全得多。
接下来,我会详细讲解unikernel,以及它们的性能优势,介绍unikernel可能适用的场景。