Amazon Firecracker: Isolating Serverless Containers and Functions
Infrastructure protection, sandboxed containers, MicroVM hypervisors– these are interchangeable terms describing emerging technologies to isolate micro-services from their underlying infrastructure. These isolation technologies aim to protect the underlying host that runs containers and functions against malicious escape and breakout attempts into other targets on the same host or on the shared infrastructure. They attempt to provide VM-level isolation while maintaining the expected speed and efficiency.
During AWS re:Invent last November, AWS announced open source Firecracker, a new virtualization technology that makes use of "MicroVMs", which are lightweight VMs. AWS shared that they’ve been using Firecracker internally to implement the multi-tenant isolation of their serverless containers (AWS Fargate) and functions (AWS Lambda) execution environments. Each Lambda function and Fargate container run with Firecracker isolation. The commercial incentive for AWS is clear, Firecracker allows to use the same virtual server for multiple containers or functions that are not necessarily from the same account. With Firecracker, a secure multi-tenancy environment can be established and be shared by different users. Technologically, Firecracker is taking a similar approach to existing isolation technologies like Openstack’s Kata Containers and IBM’s Nabla Containers. That is, using a lightweight VM construct to wrap a container, minimize the associated overhead while improving isolation.
Firecracker sparked (no pun intended) a lot of interest for several reasons. First, AWS hasn’t open sourced much of its home-grown technology to date (although it does contribute to many projects, including Kubernetes). Second, it was written in Rust, a relatively new programming language whose disciples laud for being less vulnerable to memory corruptions.
What might dampen one’s enthusiasm to use Firecracker independently, at least at the present, is that Firecracker is not OCI-compliant and doesn’t yet work in conjunction with Kubernetes or Docker. Until it does, it will have limited applicability to mainstream production deployments, though the expectation is that the open source community will resolve it - and work has already started to make it happen.
How does Firecracker work?
As organizations widely adopted serverless infrastructure using Lambda and Fargate, the time came to consider efficiency and security. Firecracker was developed to answer the question “what would a virtual machine look like if it was designed for today’s world of containers and functions”?
Firecracker implements a virtual machine manager (VMM) based on Linux's Kernel-based Virtual Machine (KVM), and provides a RESTful API to create and manage microVMs with any combination of vCPU and memory to match application requirements. Firecracker is built with minimal device emulation that enables faster startup time, provides a reduced memory footprint for each microVM, and offers a trusted sandboxed environment for each container.
Source: Firecracker on Github
A Firecracker microVM can be launched in as little as 125 ms today, making it ideal for many types of workloads, including those that are transient or short-lived.
How is Firecracker different from Kata, Nabla, and gVisor?
The need to improve container isolation isn’t new or unique to Firecracker. Kata containers, gVisor and Nabla containers are technologies that address this need and have been around longer. The main difference between the different projects lies in the virtualization technology used to form the isolation layer. Kata Containers, which pioneered this concept, selected QEMU as the basis of their virtualization technology leveraging “QEMU light”. Their “sandboxed” container runs inside a light-weight VM while using an internal agent and external “shim” to intercept runtime commands and IO needs.
Nabla containers took a different approach, uniquely leveraging unikernels, and work that was done in the Solo5 project to create a “sandboxed” environment for each container that restricts its access to the host OS. Both technologies offer OCI-compliant runtimes (kata-runtime and runNC) and allow the usage of Kubernetes as the orchestration layer, making them attractive for daily operation in large-scale environments.
Google’s gVisor project is a different beast altogether – it’s not a microVM or a hybrid VM-container, but rather creates a dedicated buffer layer for each container. The new layer is a “user space” process that addresses the container’s system calls needs, preventing direct interaction with the host OS. The gVisor runtime (runSC) is an OCI-compliant runtime and it supports Kubernetes orchestration as well.
Firecracker is the first technology that attempts to address the high-scale dynamic environment of containers and functions. It was crafted to run numerous workloads on a single machine, much more so than the other technologies whose focus was on isolation only. Boot time is low, but more importantly the potential scale exceeds the typical single server (“Host”) capacity.
It’s worth noting that the various hybrid VM-container technologies are in very early stages of adoption. They are not GA, are not field-tested in enterprise production environments, and should be regarded as experimental. This is also true of Firecracker, the newest of them all. Yes, it has the pedigree of AWS and of being the engine underneath Fargate and Lambda. But as experience has taught us, technologies that work well in proprietary cloud provider environments are not instantly ready for prime time outside those highly controlled environments (remember Kubernetes in July 2015 when it was first open sourced?).
Complementing Firecracker's isolation with Aqua MicroEnforcer
From a security standpoint, Firecracker and all isolation technologies focus on one aspect of security – they aim to restrict the blast-radius of an attack emanating from a container or function. They won’t prevent or mitigate a direct attack on application running inside containers or functions, and should not be regarded as obviating other critical aspects and layers of security.
At Aqua we’ve been securing AWS Fargate workloads since it was launched in preview, and well before anyone outside AWS knew what the underlying technology was. The concept was simple – since you have no control over or access to the host OS, as one does in “normal” VM-based container deployments, you could not run an Aqua Enforcer container alongside the other containers on a host/node. Instead, we came up with the MicroEnforcer concept, whereby we embed Aqua’s controls inside the container image during the build process.
Leveraging Aqua’s Micro Enforcer security concept into AWS Firecracker can provide superior security solution, protecting the container or function as well as its underlying infrastructure.
Let's see how this works.
We start by running Firecracker. Since at the present Firecracker doesn't support running Docker containers, we emulate one by using an Alpine sample image in Firecracker, and we embedded the Aqua MicroEnforcer binary inside:
Aqua MicroEnforcer protects the emulated Alpine container, and we can see it's deployed in the Aqua Console:
This Alpine instance is running with root privileges. Now let's run an exploit that tries to leverage the root privilege to change the file structure, something that is prevented in the default Aqua runtime policy - our Drift Prevention security control:
As we can see, the exploit was blocked by Aqua.
To sum up, Aqua complements the security posture of Firecracker-based workloads by adding visibility and security layers that expand the isolation capabilities of Firecracker. Aqua MicroEnforcer provides attack discovery and mitigation options that block attacks, mitigate malicious attempts to exploit the network, and add the needed visibility into the microservices (containers and functions) themselves.
Together, Firecracker and Aqua’s MicroEnforcer provide holistic security model that protect the workloads together with their underlying infrastructure from any type of an attack.