What Is WebAssembly — and Why Are You Hearing So Much About It?
Krustlets. Cloudflare Workers. Open Policy Agent. Shopify Apps. Microsoft Flight Simulator. The web app versions of Adobe Lightroom and Acrobat. WebAssembly (or WASM for short), is starting to show up in a wide range of tools and platforms.
Think of it as a small, fast, efficient and very secure, stack-based virtual machine that doesn’t care what CPU or OS it runs on, that’s designed to execute portable bytecode — compiled from code originally written in C, C++, Rust, Python or Ruby — at near-native speed. WebAssembly doesn’t only run in the browser: It started on the client, but is proving very useful on the server.
This is an open, industry-wide collaborative effort to combine the performance and security of an assembly-like language with the convenience of high-level languages. The Bytecode Alliance, set up to create shared implementations of WebAssembly standards, now includes major players like Arm, Intel, Google and Microsoft as well as Mozilla and Fastly — suggesting how widely WASM will be adopted.
“The promise, and excitement, is around a mix of portability and speed,” Fintan Ryan, a senior analyst at Gartner, told The New Stack.
“The specifications themselves are mature and it is in use in a number of areas, from Microsoft’s Blazor toolkit, to some browser applications,” he added. “We also see it being used, in a limited manner, within service mesh, edge devices and some edge processing.”
As a fast, secure and powerful way of running code across multiple platforms, WebAssembly is very well suited to running untrusted code from a customer or partner, whether that’s a serverless function where you want to avoid a cold start by injecting code into an already running container, an inline data transformation that runs in the database engine, an ecommerce add-on, a Kubernetes admission policy or an Open Policy Agent policy rule. Istio and Envoy support WASM as a lighter-weight and more flexible replacement for its LUA runtime for writing filters to support different protocols. Flight Simulator even uses WebAssembly modules instead of DLLs.
“Any project that has an extension mechanism will probably take advantage of WASM to do that,” Cloud Native Computing Foundation CTO Chris Aniszczyk told us.
“The promise, and excitement, is around a mix of portability and speed.”
—Fintan Ryan, a senior analyst at Gartner
This approach is a logical extension of using the browser sandbox to isolate third-party libraries—like font-rendering engines and image or audio decoders that might have bugs or vulnerabilities. But WebAssembly is also built to make it easier for developers to create safe applications (and stay safe while taking dependencies on third-party code).
Because it was designed to run in the browser and avoid the security issues that plagued Flash and Active X, WebAssembly was designed for isolation without losing performance. The browser needs to be able to parse, validate and compile WASM code while a web page is loading, and that code always runs inside a sandbox.
WebAssembly is designed to try and avoid entire classes of bugs and vulnerabilities like buffer overflows and control-flow hijacking. Because languages like C and C++ use pointers to the address in memory where the value in a variable is stored, WebAssembly code needs a secure way to get access to a very specific section of memory and nothing else. WebAssembly uses a linear block of memory, and a WebAssembly module only has access to the chunk of memory assigned to it; there’s no shared memory between modules and (at least for now), and there’s no garbage collection.
WASM separates code and data. It has a static type system with type checking and a very structured control flow designed to make it easier to write code that compiles to be safe, with linear memory, global variables and stack memory accessed separately. This is also part of how WebAssembly stays portable. Although the machine code that actually runs when WASM code executes uses registers and that will be very specific to the CPU it’s running on, WebAssembly is a stack machine; rather than using registers to store data it’s operating on, WebAssembly pops data off the stack to work on and pushes the result back onto the stack.
Currently, that data is only numbers, although there’s a proposal to add reference types — like strings, sequences, records, variants — to make it easier for WASM modules to interact with modules running in other runtimes or written in different languages. Another proposal, Web IDL bindings, will let the WASM module specify the “glue” it needs to call methods on the outside objects those new types will refer to.
A WASM module doesn’t have access to APIs and system calls in the OS. If you want it to interact with anything outside the module you have to explicitly import it, so you know the only code running is what you’ve told the module about.
The safety guarantees in WebAssembly are only as good as the sandbox, and UCSD, one of the Bytecode Alliance members, has created a formal verifier to check the accuracy of the sandbox implementation, Veriwasm.
There will still be vulnerabilities in WASM, Bytecode Alliance representative Till Schneidereit told us. “None of us are infallible. The question is how do you handle it and what are you doing to make it less likely and to mitigate the fallout?” For many of the emerging use cases for WebAssembly, he said, “security is just the ticket to entry”.
Out of the Browser and into the Cloud
When WebAssembly is running inside the browser, the browser handles its access to operating system features. For running WebAssembly outside the browser, like on a server or an IoT device, some of the issues will look very familiar to cloud native developers, such as handling the concept of a file system (which you need for saving code, configuration and shared data) on services that have no file system. Giving code full access to the operating system doesn’t just open up the possibility of attacks; it also ties the code to that specific operating system.
To avoid that, WebAssembly uses the WebAssembly System Interface (WASI). It’s a modular set of system interfaces that looks like an abstracted OS, with low-level interfaces like IO and high-level interfaces like cryptography, keeping WebAssembly code portable.
This improves security because it isolates modules and gives them only fine-grained permissions for particular parts of the file system (or other resources) and system calls; different modules are isolated from each other and limited in what they could pass on to any malicious code that attempted privilege escalation. It can also improve performance, for a scenario like copying data between containers; instead of having to move data between user and kernel space, send it across the network and then reverse the process, the data can just be piped into a sidecar, using a faster and simpler calling mechanism.
As Docker co-founder Solomon Hykes tweeted when WASI was announced “If WASM+WASI existed in 2008, we wouldn’t have needed to created Docker.”
If WASM+WASI existed in 2008, we wouldn’t have needed to created Docker. That’s how important it is. Webassembly on the server is the future of computing. A standardized system interface was the missing link. Let’s hope WASI is up to the task! https://t.co/wnXQg4kwa4
— Solomon Hykes (@solomonstre) March 27, 2019
RedHat is building another runtime (also based on Wasmtime) that can use a trusted execution environment like Intel SGX to run sensitive workloads on untrusted hosts, as part of the Confidential Computing Consortium’s Enarx project.
Other runtimes include:
- Wasmer, a server-side runtime with support for multiple compilers including LLVM.
- WAVM uses LLVM to compile WebAssembly code to machine code.
- Wasm3 also focuses on embedded app devices.
- Second State’s WasmEdge (known as SSVM before it was accepted into the CNCF sandbox) is specifically targeted at in-car applications.
- Platform approaches like Wasmcloud, an actor runtime (formerly known as WaSCC) that builds on top of WebAssembly for creating distributed systems written in AssemblyScript, TinyGo or Rust that binds WebAssembly modules to cloud services.
With so many different approaches, performance can differ between runtimes — and the increasing interest in WebAssembly means we’re in a Pre-Cambrian explosion of tools, with new options emerging and some older tools stopping development or not supporting the full specification. These comprehensive benchmarks are a helpful survey of what’s still current as well as how quickly the ecosystem is developing, but both WASI and WebAssembly itself are a work in progress.
This amount of experimentation is very healthy for the WebAssembly ecosystem, Schneidereit suggested: “We need a range of different people trying different takes on what a great solution looks like. And I think it’s fantastic for developers: they can mix and match different approaches to solving different aspects of their use cases and have a pretty wide range of different implementations to choose from.”
He acknowledges this does put a burden on developers to make decisions about which approach to take, and as W3C standardization continues some of them will be superseded by proposals like WebAssembly components and module linking. “We will eventually see some approaches emerging as winners, others fading away. In the long run, people are not interested in having proprietary niche solutions for everything they could possibly target.”
Revolutionizing Cloud Dev
WebAssembly is simplest to work with when it’s supported as part of a platform, like the CLI in Wasmcloud or the rpk tool in Redpanda Transforms.
“We will eventually see some approaches emerging as winners, others fading away. In the long run, people are not interested in having proprietary niche solutions for everything they could possibly target.”
—Till Schneidereit, Bytecode Alliance
Beyond that, the developer experience for WASM often involves custom bindings, possibly complex toolchains and multistep workflows. Better tools are starting to arrive, and not just for Rust. More than a dozen languages have compilers that can produce WebAssembly binaries — but they’re still fragmented.
Among the new tools:
- Binding generators like wasm-bindgen and witx-bindgen automatically create bindings and glue code for you.
- A Yeoman WASM project generation tool
- Bindle, which makes it easier to store and distribute WASM modules together
- Experimental options, like the WebAssembly Gateway Interface (WAGI) for building WebAssembly microservices using CGI.
“It is still pretty nascent, there is a lot of (quickly improving) toolchain setup work to do which can feel daunting for some,” Ryan noted. “If you come from a systems background, it feels fine; from a web background, less so. The Rust community, in particular, is doing a lot of work in this space. We also see interesting work happening with AssemblyScript.” (That’s a variant of TypeScript that compiles to WebAssembly).
For WebAssembly to go mainstream, it will need to be as easy to compile a WebAssembly binary as any other binary and if the tooling is easy to integrate into the way developers already work, as well as being available in the environments developers want to target.
“We are actively working on production-quality of implementations of all these things so that we can get them into the hands of developers, integrated into environments that developers want to target.”
For some developers, though, WebAssembly will look more like a functional packaging decision. Krustlets and Blazor already treat WASM as a way of delivering a complex environment: with Krustlet that’s a Kubernetes node, with Blazor it’s .NET. Blazor puts the .NET runtime into a WebAssembly sandbox, so as long as the libraries an application requires are included pretty much any .NET code can run inside WASM in the browser. WebContainers puts Node.js inside WebAssembly to run Visual Studio Code (think of it as an alternative to GitHub Codespaces).
That kind of packaging will give WebAssembly enormous scope. TC39 co-chair Brian Terlson is “very bullish” on WebAssembly because in 10 years’ time it could be a foundational part of cloud computing infrastructure that drastically changing the programmability model.
“It’s a future portable executable format that has a lot of really nice features: very lightweight, really cross-platform and combined with the Web Assembly System Interface you could imagine a future where you don’t need Node or whatever, because you can just build a native executable that has Node or Deno ride along with it,” Terlson told us. “You can run little WebAssembly programs on the edge, very few hops away from where your customers are for super-low latency.”
A Productivity Boost
But the big advantage for cloud development isn’t just security for untrusted code. It’s productivity for developers and for the cloud service providers who build SDKs for them, Terlson suggested.
Imagine a developer trying out a cloud messaging service like Azure Service Bus; they want to test their code by dropping a message into the queue, and they want that to be easy in whatever language they’re using. Just using the Azure CLI means downloading a Python interpreter because that’s the language it’s implemented in. If it delivers the long-awaited “write once, run anywhere” promise, WebAssembly could turn that on its head.
“We don’t have a simple tool to just throw a message in the queue, and developers really demand that these tools be built into their development workflow,” Terlson said. “Azure supports so many different languages and we can’t be writing the same tools over and over again in each individual language. We need a technology that would let us ship a very slim, simple tool in some kind of envelope that lets us package it and expose it in many different languages. WebAssembly with WASI could be that technology.” (Fastly is already taking advantage of a very early version of that kind of portable tooling as it builds WebAssembly tool, Schneidereit told us.)
Scale the idea up, and Terlson believes WebAssembly could dramatically simplify the cloud programming model.
“I think there’s going to be a future where WebAssembly, combined with some runtime for cloud native applications, is going to clean up the story significantly,” he said. “I can bring whatever language I want. I can bring whatever PaaS infrastructure and the WebAssembly runtime will glue it all together with very little work. I can run my app in the cloud, I can run my app on the edge, I can run it locally. It doesn’t matter to me as a developer; it just runs.”
Correction: This article previously included mention of WaSCC, which is now known as Wasmcloud.