gVisor:谷歌发布的一个用于提供安全隔离的轻量级容器运行时沙箱

  • Daniel Bryant
  • 谢丽

2018 年 5 月 21 日

话题:DevOps语言 & 开发Kubernetes

看新闻很累?看技术新闻更累?试试下载 InfoQ 手机客户端,每天上下班路上听新闻,有趣还有料!

谷歌发布了一种新型沙箱gVisor,可以用于为资源占用较少、不需要运行完整 VM 的容器提供安全隔离。gVisor 的核心是一个使用 Go 编写的开源用户空间内核,与现有的容器技术相比,其设计做了不同的权衡,它实现了 Linux 系统表面的主要部分。该项目包含集成了 Docker 和 Kubernetes 的OCI运行时“runsc”。

据 gVisor 项目的 GitHub README介绍,gVisor 是一个作为普通非特权进程运行的内核,支持大多数的 Linux 系统调用。就像在 VM 中一样,在 gVisor 沙箱中运行的应用程序有自己的内核和虚拟设备,与主机和其它沙箱区分开来。通过拦截应用程序系统调用并作为客户内核运行,gVisor 提供了强隔离边界,可以将其视为极致半虚拟化的操作系统,“与完整的 VM 相比,资源占用更灵活,固定成本更低”。不过,这种灵活性牺牲了性能和兼容性:对于频繁进行系统调用的工作负载,gVisor 的性能可能会差一些;虽然 gVisor 实现了 Linux 系统 API 的一大部分(目前 200 个系统调用),但有几个系统调用和参数还不支持(/proc 和 /sys 文件系统的某些部分),也就是说,并不是所有的应用程序都可以在 gVisor 内运行

gVisor 分层(图片来自项目的 GitHub 库

谷歌云平台(GCP)博客关于 gVisor 的公告指出,容器已经彻底改变了组织开发、打包和部署应用程序的方式,但是同时,暴露给容器的系统表面很宽,许多安全专家“不建议在容器中运行不受信任的应用程序或者潜在的恶意应用程序”。为了佐证这种说法,该博文引用了 opensource.com 的一篇文章“Docker 容器真的安全吗?”,不过,需要注意的是,这篇文章是 2014 年发表的,从那时到现在,容器安全领域的许多东西都发生了变化,尤其是和 Docker 相关的

不过,目前的容器技术仍然有许多广为人知的安全挑战,我们之前发表在 InfoQ 的文章“Docker 与高安全性的微服务:总结 Aaron Grattafiori 于 DockerCon 2016 的发言”中罗列过。其中一个主要的问题是,从单一共享内核获得效率和性能意味着容器逃逸可能成为一个漏洞。相应地,谷歌认为,人们越来越希望运行异构性更高、信任度更低的工作负载,这就引发了人们对于沙盒容器的兴趣,“容器可以帮助我们在主机操作系统和在容器中运行的应用程序之间提供一个安全的隔离边界”。

gVisor 限制了应用程序可访问的主机内核表面,同时又让应用程序可以访问它们希望访问的所有特性。和大多数内核不同,gVisor 并没不假定或需要一套固定的硬件资源;相反,它利用已有的主机内核功能,作为一个普通的用户空间进程运行。gVisor 会拦截应用程序的所有系统调用,并做必要的工作为它们提供服务。与其他容器技术相比,一个关键的区别是,gVisor 不是简单地把应用程序系统调用重定向给主机内核,而是实现了大多数内核原语(信号量、文件系统、Futex、管道、mm 等),并基于这些原语实现了系统调用处理程序。

为了提供纵深防御,限制主机系统表面,gVisor 运行时被分成了两个独立的进程。第一个是 Sentry 进程,它包含内核,负责执行用户代码,处理系统调用。第二个是Gofer,它是一个文件系统操作代理,超出沙箱(非内部 proc 或 tmp 文件、管道等)的文件系统操作会通过9P 连接发送给它。

gVisor Sentry 和 Gofer 架构(图片来自项目的 GitHub 库

Sentry 需要一个平台来实现基本的上下文切换和内存映射功能。现在,gVisor支持两个平台Ptrace平台,使用SYSEMU功能执行用户代码,不需要执行主机系统调用;KVM 平台(试验性),使 Sentry 充当客户 OS 和虚拟机监视器(VMM),并在两者之间无缝地来回切换。

gVisor 运行时通过“runsc”(“run Sandboxed Container”的缩写)集成了 Docker 和 Kubernetes,遵循 OCI 运行时 API 标准。runsc 运行时可以和runc互换,后者是 Docker 的默认容器运行时。在 Kubernetes 中,大多数资源隔离发生在pod层,这让 pod 特别适合作为 gVisor 沙箱的边界。Kubernetes 社区目前正在规范化沙箱 pod API,但是,现在已经提供了试验性支持。runsc 运行时可以通过cri-o或者cri-containerd项目在 Kubernetes 集群中运行沙箱化的 pod。这两个工具会把Kubelet的消息转换成 OCI 运行时命令。

至于相关项目,Kata 容器是一个开源项目,使用“非常轻量级的”VM 来保证容器隔离的资源占用最小化。和 gVisor 类似,Kata 包含一个兼容 Docker 和 Kubernetes 的 OCI 运行时。在 HackerNews 上,有许多关于在这些技术之间进行取舍的讨论,其中有个用户表示“在 [这些不同的沙箱技术] 之间进行取舍主要考虑的是兼容性、安全边界健壮性和性能”。

gVisor 使用Go 语言编写,选择它是考虑到它的内存和类型安全性。需要注意的是,gVisor 目前只能在 x86_64 Linux 3.17+ 上构建和运行,而且在沙箱内只支持 x86_64 二进制文件(即不能运行 32 位二进制文件)。

gVisor 的 GitHub 库提供了更多信息,希望参与讨论的工程师也可以加入谷歌讨论组

查看英文原文Google Release "gVisor", a Lightweight Container Runtime Sandbox Used to Provide Secure Isolation

DevOps语言 & 开发Kubernetes