Product Releases
August 21, 2023
6 min read

WebAssembly in Kong Gateway 3.4

hisham
Hisham Muhammad
Software Engineer & Product Manager (WebAssembly), Kong

Perhaps the most exciting feature introduced in Kong Gateway in recent years is the addition of WebAssembly support.

WebAssembly (or Wasm) was originally developed to bring additional languages beyond JavaScript into the browser. However, nothing stops it from being used in the backend as well! With WebAssembly in Kong Gateway, you’ll be able to build and deploy Wasm filters using languages such as Rust and Go, and configure filter chains to operate on your Kong routes and services.

What is WebAssembly?

WebAssembly is an industry-standard specification for sandboxed language runtimes. This specification defines several things:
  • Its own binary format for compiled bytecode files, called .wasm. This is not unlike Java .class files, but it’s language-agnostic: you can develop for any language you like, as long as you have a compiler for that language which generates .wasm files.
  • A multi-language virtual machine (VM) for running said bytecode. This is not unlike Microsoft .NET, but it is a W3C project with multiple implementations of Wasm VMs, mainly coming from the various browser vendors.
  • APIs for embedding the VM into a host application with communication between code running in the VM and the host. This is not unlike LuaJIT, but there is more of a focus on sandboxing, to protect the host from code running in the VM.
We’re excited about adopting WebAssembly in Kong Gateway because it will open new possibilities for extending the gateway with different languages, in a way that is integrated with the core application. This means we’ll be able to support more languages over time as they get Wasm support without additional operational overhead.

For developers wishing to extend Kong Gateway using their favorite language, an important benefit is that the growing Wasm ecosystem promotes standard APIs such as WASI and Proxy-Wasm, which means more opportunities for code reuse, leading to faster development.

Wasm filters using Proxy-Wasm

Kong Gateway 3.4 supports WebAssembly extensions in the form of Wasm filters. Each filter is a WebAssembly module (that is, a single, easy-to-deploy .wasm file) which implements one or more event handlers for various stages of a request lifecycle.

You write a filter by developing a module using the Proxy-Wasm SDK available for your favorite language. Proxy-Wasm is an emerging standard API for coding Wasm filters. It consists of two parts: an ABI (Application Binary Interface) for host applications to implement, and client SDKs for various languages. Kong Gateway includes its own implementation of the Proxy-Wasm host ABI, via Kong's WasmX project. Using WasmX, Kong Gateway can run Wasm filters written using any third-party Proxy-Wasm client SDK.

Wasm filters can perform all sorts of proxying operations, such as adding or removing headers, modifying the request body, running background timers, calling out subrequests, and leveraging code from third-party libraries that can be compiled into WebAssembly. They provide a powerful interface for extending Kong Gateway in a safe, sandboxed way.

You can freely combine filters in your Kong Gateway configuration by defining filter chains, which are nothing more than a list of filters in a given order, alongside their configuration. These filter chains can be applied to both Routes and Services, and for any given endpoint its Service's and Route's chains are combined to form a larger chain of filters. The configuration model is extremely flexible: you can define the order of execution of filters in a chain yourself, and even apply the same filter multiple times with different configurations.

Let's run a filter

To get you started on coding Wasm filters, we’ve created "hello-world"-style repositories implementing filters in Rust and Go. These are intended as templates, but they’re complete, working examples: we can build them as-is to have an example filter to play with.

Let's take the Go filter and give it a spin.

First, you need your regular native Go development environment. But we also need a compiler that can generate .wasm files. We recommend TinyGo. Once TinyGo is installed, you’re now ready to clone the repository and build the filter:

git clone https://github.com/kong/proxy-wasm-go-filter-template
cd proxy-wasm-go-filter-template
make

That will produce a file called my-go-filter.wasm. Let's store it in a folder called "filters", to which we will later point in our Kong configuration:

mkdir ./filters
mkdir ./config
	cp my-go-filter.wasm ./filters

Next, let's create a basic Kong configuration which includes a filter chain. In this simple example, the chain will be attached to a route and will contain a single filter. Let's do this by creating a declarative configuration file in YAML called ./config/kong.yml:

_format_version: '3.0'
services:
  - name: my-wasm-service
    url: http://mockbin.org
    routes:
    - name: my-wasm-route
      paths: ["/"]
      filter_chains:
      - filters:
        - name: my-go-filter
          config: >-
            {
              "my_greeting": "Hello from Kong using WebAssembly!"
            }

Now we have everything we need to run a test. Let's spin up a container and configure it via environment variables to run a minimal test, like so:

docker run -d --name kong-wasm \
-v $PWD/config:/kong/config \
-v $PWD/filters:/kong/wasm \
-e KONG_WASM=on \
-e KONG_WASM_FILTERS_PATH=/kong/wasm \
-e KONG_DATABASE=off \
-e KONG_DECLARATIVE_CONFIG=/kong/config/kong.yml \
-p 8000:8000 -p 8001:8001 \
kong/kong:nightly

Our container should be live and the Proxy-Wasm filter is ready to be used:

$ http --headers http://127.0.0.1:8000/echo

HTTP/1.1 200 OK
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Thu, 03 Aug 2023 19:28:27 GMT
Vary: Accept-Encoding
Via: kong/3.4.0
X-Greeting: Hello from Kong using WebAssembly!
X-Kong-Proxy-Latency: 1
X-Kong-Upstream-Latency: 342

Our filter executed and it added a new header called X-Greeting to the response, based on a configuration value which is provided to the filter as a JSON object containing a key called "my_greeting".

To further illustrate the use of the Proxy-Wasm SDK with Kong Gateway through a more fleshed-out example, we’ve also implemented simplified versions of a rate-limiting filter in both Rust and Go. Do check them out if you want to see more examples of event callbacks and Proxy-Wasm functions in action.

Now: The cutting edge

WebAssembly support for Kong has been in the works for a long time and continues to evolve. We gave a sneak preview last year at Kong Summit, we announced its inclusion in the release as a beta feature, and by the time you’re reading this the feature has progressed already. And we hope to pick up the pace even more as we get feedback from our customers and the OSS community. So, if you want to give WebAssembly support a spin and have access to the latest features, fixes and performance improvements, we recommend you check out our nightly container builds, which you can pull using `kong/kong:nightly`.

Being beta means that interfaces might still be subject to breaking changes. For this reason, even though Kong Gateway Enterprise 3.4 is an LTS release, the WebAssembly beta is not subject to long-term support.

The future: What's next?

We really want your feedback about this feature, so we can graduate it to a GA (generally available) feature in a future release.

Give it a try, play with writing filters, let us know any surprises you run into — good or otherwise! What did you like when writing filters? What seems to be missing? Anything missing or confusing in the documentation? Which other languages would you like to see supported?

We also encourage you to share your filters so that we as a community can start building a knowledge base around WebAssembly in Kong Gateway. A great way to do it is to post your filters on GitHub and then talk about them in Kong Nation!