We have several services and tools that accept either arbitrary binary input, or what amounts to some form of code (be it a DSL, as in the case of the easytimeline or score extensions, or directly code as in the case of wikifunctions or the shellbox-constraints service), from basically any user on the internet.
Up to now, we have mostly relied on container-level isolation to ensure separation of such payloads from the rest of our infrastructure. The rising frequency of LPEs on Linux, and thus the risk of container escape, makes us want to improve the level of isolation of such payloads, so that a compromise of a payload doesn't easily result in a physical host compromise; with the only exception being wikifunctions, that uses WASM to sandbox the application code.
There's a couple of solutions for this, gvisor and kata-containers. gVisor is basically a user-space simulated kernel which only reproduces a subset of the linux syscalls and adds a sentry layer to it, while kata-containers spawn a VM in which the containers are executed. gVisor provides a smaller footprint in terms of memory/cpu overhead, and faster startuptimes, at the expense of a slightly higher runtime overhead. Kata-containers, especially on hardware that supports hardware virtualization, have a lower performance overhead at the cost of added complexity and more resource consumption.
It is probably a good idea long-term to consider the strenghts of both approaches, but for now, we don't need both.
Specifically, given none of the deployments we consider critical from a security POV have very strict latency requirements, the simplicity and resource frugality of gVisor seem to make it the better candidate for our goals.
This umbrella task should spawn all the tasks needed to introduce gvisor as a runtime for our kubernetes clusters.
In order to run gvisor and make it available for our kubernetes clusters, we need to do the following:
- Ensure we import the right gvisor sets of packages
- Conditionally configure containerd to be able to run one or more runsc-based runtimes
- Automatically label nodes that are configured to run gvisor-based payloads
- Configure said runtimes according to different risk profiles we want to run
- Create the corresponding RuntimeClass objects
- Add validating admission policies to ensure high-risk payloads only run with the aforementioned runtimeclasses
- Add the needed annotations to the deployments to ensure they can work under gvisor (for instance, we use shared pod volumes for php-fpm and apache to communicate via unix sockets)