面向Serverless的安全虚拟化简介(LXC,AWS Firecracker,gVisor)
面向Serverless的三种安全容器简介
LXC
[]: https://www.cnblogs.com/xidongyu/p/5767020.html
LXC又名Linux container,是一种虚拟化的解决方案,这种是内核级的虚拟化。
namespace
Linux Namespaces机制提供一种资源隔离方案。PID,IPC,Network等系统资源不再是全局性的(在Linux2.6内核以前是全局的),而是属于特定的Namespace。每个Namespace里面的资源对其他Namespace都是透明的。namespace是container中使用到的重要技术之一,是对系统资源的操作上的隔离。使Guest-OS1的操作对Guest-OS2无法产生影响。
下面是3.8以上的内核实现的namespace:
- mount
- UTS
- IPC
- Net
- Pid
- User
user
User namespace中使用到了map转换,由于container并不是真正的虚拟化,所以在Guest-OS中创建的root用户会被映射到Host-OS中的普通用户中去。root用户在自己的namespace下创建了一个文件,那这个文件的所有者ID应该是0,当时在磁盘上存的时候文件UID会被转换为kuid,并且所有者ID为1000。想说名一点是在Guest-OS下你是个root用户,但是在Host-OS你只不过被转为一个普通用户而已。因为我们知道在Host-OS下已经有一个root用户了。
AWS Firecracker
AWS Firecracker是一款由 AWS开源的轻量级虚拟化运行环境,客户可以在 AWS 云上和本地环境中使用它。Firecracker MicroVM 同时具备传统虚拟机的安全性和工作负载隔离能力以及容器的速度和资源利用率。运行在为 Firecracker 优化过的 Amazon 裸金属 EC2 服务器上的 MicroVM是多租户容器服务的理想选择,可以为最新的微服务或无服务器架构的现代应用提供方便、敏捷的开发和部署环境。
专业术语
- 轻量级虚拟机(以下简称 MicroVM,它没有模拟完整的计算机硬件设备,只实现了运行现代化工作负载的必要功能)
- 设备模型(Device Model 指需要 Hypervisor 模拟仿真的硬件设备)
- 无服务器(Serverless 指开发者不用再考虑服务器运行环境了,代表服务有 AWS Lambda)
虚拟化与安全历史
QEMU
- X86平台虚拟化的转折点则发生在2001年,VMware 发布了 ESX,法国著名程序员Fabrice Bellard编写了开源设备模拟器软件QEMU(Quick EMUlator)的第一个版本,实现了全虚拟化。
- 后来 QEMU 通过集成 KVM 与 XEN 技术,广泛用于虚拟机管理监视器,并提供接近原生的半虚拟化性能。现今已成为了开源领域 VMM 的事实标准。作为通用设备模拟器,它在设计上做到了尽可能兼容任何硬件平台,同时各种高级特性(例如设备热插拔)也在一直不断丰富,并于2019年宣称可以模拟所有设备。
- 风光的背后是,一些统计显示2013至2018年间 QEMU 报告的 CVE 漏洞数量由49%来自它所模拟的设备,其中最为著名的 VENOM ”毒液”漏洞就是由它所模拟的软驱控制器导致。
- 现代硬件设备与 KVM 的成熟使得需要 QEMU 模拟的设备越来越少,对大量其它体系结构(事实支持 Intel、AMD、ARM足以)和陈旧设备(例如软驱、打印机串口)的模拟,而此时的 QEMU 还依然在做加法,截止到2019年整个项目的代码量超过了三百万行(仅列出 C 代码、头文件与 Makefile,不包括注释),总文件数量超过一万。
传统虚拟机技术
- 虚拟化技术经过了几十年的发展演进,从全虚拟化,半虚拟化,到硬件辅助虚拟化(例如Intel VT-x技术),再到如今以硬件卸载虚拟化(例如借助 Intel VT-d 通过 SR-IOV 方式卸载 IO 请求到硬件加速卡)。CPU 不需要预留计算资源给设备模型,而以前绝大部分设备都需要使用 QEMU 模拟(带来 CPU 额外开销),从而提升性能表现。
- 其中 AWS 的 Nitro 架构经过几代演进之后,现在的版本基于 KVM 虚拟化自研 VMM 以及配套专用硬件加速卡,这使得虚拟化环境下获得几乎与裸金属物理机一样的性能,大规模的这项技术用于新一代 EC2 实例,获得了极致的性能和安全可靠性。
容器沙箱技术
近年来大火的 Docker 容器,与传统虚拟机的捕获 – 模拟(Trap – and – Emulate)技术路线不同,容器最早的技术原型为 Unix 系统的 chroot 操作(诞生于1979年代),从而限制进程对指定根目录之外的文件访问。后来经历了 FreeBSD Jails、OpenVZ、LXC、libcontainer 等技术逐步演进,形成了完整的一套应用运行环境沙箱隔离技术。而 Docker 则通过一系列创新,将古老的容器沙箱技术上升到了一个新的高度。在笔者看来这其中主要包括但不局限于:
- OCI (Open Container Initiative) 规范了运行时标准
- 镜像分层设计与 OCI Image Spec 镜像规范
- 实现了一个轻量级容器运行时 RunC,它拥有简单运行容器所需要的全部组件
- 贡献给 CNCF 社区的 containerd 运行时生命周期管理程序
但是,
- 容器的安全隐患从这项技术诞生的第一天起就一直存在。Docker容器技术采用共享宿主机内核方式运行,利用内核特性实现对不同用户的命名空间进行隔离(6种方式),使用 CGroups进行硬件资源分配与限制,POSIX Capabilities进行 root 权限分割等,Seccomp 限定系统调用。虽然有组合了很多种技术,但实现原理决定了容器的其隔离性、封闭性还是远远低于拥有独立 GuestOS 的虚拟机。
- 由于操作系统内核漏洞,Docker 组件设计缺陷,以及不当的配置都会导致 Docker 容器发生逃逸,从而获取宿主机权限。由于频发的安全及逃逸漏洞,在公有云环境容器应用不得不也运行在虚拟机中,从而满足多租户安全隔离要求。
- 而分配、管理、运维这些传统虚拟机与容器轻量、灵活、弹性的初衷背道而驰,同时在资源利用率、运行效率上也存浪费。
AWS 同样面临着与 Docker 容器类似的技术困扰,2014年11月推出了 AWS Lambda 服务。为了提供无服务器计算下安全的体验,最初通过后台为每个租户置备独立的 EC2 实例从而实现与其它租户的强安全隔离。随着 AWS Lambda 服务的增长,开发团队意识到需要一个新技术提供高安全性、灵活性和效率的运行时环境给类似 AWS Lambda 和 Fargate 这样的服务。
AWS Firecracker
作为一款轻量级虚拟机,Firecracker 仅仅实现了以下功能:
- 基于 VirtIO 的网络,磁盘和套接字驱动(virtio-net,virtio-blk,virtio-vsock),分别用于 MicroVM 的网络与磁盘 IO 访问,以及 MicroVM 上的 AF_VSOCK 套接字与宿主机的 AF_UNIX 套接字通信,从而实现 MicroVM 内运行的应用传递 vhost 内核代码到宿主机的通信
- 可编程的间隔计时器
- KVM 时钟
- 串口终端控制台(例如 /dev/ttyS0)
- 仅包含关机键的键盘
安全
安全始终是 AWS 关注的头等大事。虚拟化作为一项最基础的服务,其本身的安全性格外重要。从主要两个维度降低风险:
- 抛弃 QEMU 使用的 C 语言,选择内存安全的 Rust 作为开发语言
- 基于 crosvm 使用极简设备模型,模拟尽可能少的必要设备,减小暴露的攻击面
高性能
得益于极简的设备模型, Firecracker 取消了 SeaBIOS (开源的 X86 BIOS),移除了 PCI 总线,取消了 VGA 显示等等硬件模拟,严格的说它甚至不是一台完整的虚拟计算机。而 Firecracker 运行的 GuestOS 使用的也是 AWS 定制过的精简 Linux 内核,同样裁剪掉了对应的设备驱动程序、子系统等等。因此叫它 MicroVM,其启动步骤和加载项要远远少于传统虚拟机。因此 Firecracker 目前已经能提供小于125ms 的 MircroVM 启动速度,每秒150台的启动能力,小于5MiB 的内存开销,并发运行4000台的极限承载容量(AWS i3.metal EC2 作为宿主机),以及热升级能力等。
同类项目
一类是基于在已有的成熟 VMM,进行编译选项裁剪和 GeustOS 精简,同样使用虚拟化技术解决问题。这类方案包括基于 QEMU-KVM 的 Hyper.sh RunV,Intel Clear Container,Pouch Container 等,基于 VMware ESXi 的 vSphere Integrated Containers,以及 Microsoft 的 Hyper-V Container。这类方案的主要不足源于这些 Hypervisor 过去用在传统虚拟机,并不是面向无服务器计算这类的现代化工作负载而设计开发,因此在安全、性能、开销方面可能会存在先天不足。
另一类则完全不使用虚拟机,以 Google 的 gVisor 以及一众 Unikernel 技术为代表gVisor 引入了进程虚拟化的思想,去掉了设备模型,将虚拟化的边界移到了系统调用层面,从而减少传统设备虚拟化的开销。而代价却是有大量的 Linux 系统调用需要沙箱处理,暴露了更多的攻击面(目前已实现了数百个系统调用)。而 Unikernel 则源于90年代的操作系统微内核理念,随着近年来容器技术的走红,这项技术也越来越被人关注(例如 Nabla container)。其核心思想是将 Linux 的宏内核拆分成为多个库,只打包应用依赖的库到微内核镜像中。每个应用拥有独立的微内核,从而提升性能,降低开销,减少攻击面。不过这些 Unikernel 项目大部分处于早期阶段,作为容器技术的竞争对手,其部署、管理以及与 OCI 的兼容性都会是一大考验。
gVisor
[]: http://dockone.io/article/5280
传统Linux容器并不属于沙箱环境
- 传统Linux容器当中运行的应用程序采用等同于常规(非容器化)应用程序的系统资源访问方式:即直接对主机内核进行系统调用。内核以高权限模式运行,允许其与必要硬件交互并将结果返回给应用程序。
- 立足内核对应用程序所能访问的资源作出一些限制。这些限制通过Linux cgroups与命名空间来实现。然而,并非所有资源皆可通过这种方式加以控制。此外,即使存在这些限制,内核仍然在很大程度上暴露在恶意应用程序的攻击范围之内。
- 像seccomp过滤器这类内核功能可以在应用程序与主机内核之间建立更好的隔离机制,但其要求用户创建预定义的系统调用白名单。在实践当中,我们往往很难预先确定哪些应用程序需要哪些系统调用。
现有基于虚拟机的容器技术
Kata容器是一个开源项目,其利用精简化虚拟机以尽可能减少资源占用量,同时最大限度提高容器隔离能力。与gVisor一样,Kata也包含与Docker及Kubernetes相兼容的开放容器倡议(简称OCI)运行时。
利用gVisor建立沙箱化容器
gVisor的核心为一套运行非特权普通进程的内核,且支持大多数Linux系统调用。该内核使用Go编写,这主要是考虑到Go语言拥有良好的内存管理机制与类型安全性。与在虚拟机当中一样,gVisor沙箱中运行的应用程序也将获得自己的内核与一组虚拟设备
gVisor通过在用户空间内拦截应用程序系统调用并充当访客内核,gVisor能够提供强大的隔离边界。而与需要一组固定资源的虚拟机不同,gVisor能够随时适应不断变化的资源条件,这一点更像是普通Linux进程。gVisor很像是一种超虚拟化操作系统,其与完整虚拟机相比拥有更灵活的资源利用方式与更低的固定成本,但这种灵活性的代价是其系统调用成本更高且应用程序兼容性略差。