A tour of the WasmPlugin resource in Istio 1.12
WebAssembly (Wasm) is a fast, efficient, and portable binary instruction format for programming languages that helps users to extend their web applications as well as their server side applications. It provides an embeddable and safe execution environment for platform extensions and has been gaining momentum with popular cloud-native technologies including Kubernetes, Envoy Proxy, and Istio (see the new WasmPlugin resource in Istio 1.12 here).
Over the past few years, we’ve been helping to drive excitement and development around the potential of Wasm across the industry, specifically as a way to extend an Envoy-based data plane in API Gateways and service meshes. In March of 2020, Christian Posta published a blog about Web Assembly deployment for Istio, where users can define their WebAssembly extensions using a declarative format. The declarative custom resource mentioned in the blog was later renamed to the WasmDeployment resource and became a first class API in Gloo Mesh in late 2020.
The WasmDeployment custom resource along with the WebAssembly wasme tooling allows users to easily build Wasm OCI (Open Container Initiative) images and publish these images to the free WebAssemblyHub. These tools have enabled many of our enterprise users to customize the capabilities of an Istio data plane for backward compatibility or interoperability. Some of the top use cases we’ve recently seen are focused around security, metrics, and logging. In this blog post, we dive into deploying Wasm filters with the new WasmPlugin resource in Istio 1.12.
Istio 1.12’s WasmPlugin
In the recent 1.12 release, Istio introduced a new WasmPlugin resource to declaratively deploy Wasm filters in Istio. This resource has a similar configuration to the WasmDeployment custom resource which has been in Gloo Mesh since late 2020. Upon installation of Istio 1.12, you will notice a total of 14 Custom Resource Definitions (CRDs) including the new WasmPlugin custom resource as part of the extensions group.
kubectl get crd NAME CREATED AT authorizationpolicies.security.istio.io 2021-11-30T14:43:19Z destinationrules.networking.istio.io 2021-11-30T14:43:19Z envoyfilters.networking.istio.io 2021-11-30T14:43:19Z gateways.networking.istio.io 2021-11-30T14:43:19Z istiooperators.install.istio.io 2021-11-30T14:43:19Z peerauthentications.security.istio.io 2021-11-30T14:43:19Z requestauthentications.security.istio.io 2021-11-30T14:43:19Z serviceentries.networking.istio.io 2021-11-30T14:43:19Z sidecars.networking.istio.io 2021-11-30T14:43:19Z telemetries.telemetry.istio.io 2021-11-30T14:43:19Z virtualservices.networking.istio.io 2021-11-30T14:43:19Z wasmplugins.extensions.istio.io 2021-11-30T14:43:19Z workloadentries.networking.istio.io 2021-11-30T14:43:19Z workloadgroups.networking.istio.io 2021-11-30T14:43:19Z
To get started, let’s deploy the httpbin and sleep examples from the Istio distribution to the default namespace:
kubectl apply -f samples/sleep/sleep.yaml kubectl apply -f samples/httpbin/httpbin.yaml
Download the Gloo Mesh Open Source meshctl CLI if you don’t have it yet. Using the meshctl CLI is not required for Istio, but it is proven to be the easiest way to build a Wasm plugin.
curl -sL https://run.solo.io/meshctl/install | sh
In my environment, I have meshctl version 1.2.4:
meshctl version { "client": { "version": "1.2.4" }, "server": null }
Use the meshctl wasm
command to create a simple wasm project called “myfilter”:
meshctl wasm init myfilter --language=assemblyscript
This will create the myfilter directory with scaffold code in assemblyscript. The filter simply adds “hello: world!” to the response header and you could modify it to add your own custom logic based on your business needs.
Use the meshctl wasm
command to build a simple wasm image:
cd myfilter meshctl wasm build assemblyscript -t webassemblyhub.io/linsun/helloworld:latest
Push the image to the WebAssembly Hub. Log in to the Hub if you haven’t logged in first.
Deploy a simple WasmPlugin custom resource to your Kubernetes cluster. Note the selector selects the httpbin service by matching the “app: httpbin” label and the URL points to the pushed image to webassemblyhub.io.
cat wasm-plugin-helloworld.yaml apiVersion: extensions.istio.io/v1alpha1 kind: WasmPlugin metadata: name: helloworld namespace: default spec: Selector: matchLabels: app: httpbin pluginName: add_header url: oci://webassemblyhub.io/linsun/helloworld:latest kubectl apply -f wasm-plugin-helloworld.yaml
Test httpbin from the sleep pod:
kubectl exec -it deploy/sleep -c sleep sh -- curl httpbin:8000/status/200 -v * Trying 10.96.77.189:8000... * Connected to httpbin (10.96.77.189) port 8000 (#0) > GET /status/200 HTTP/1.1 > Host: httpbin:8000 > User-Agent: curl/7.80.0-DEV > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < server: envoy < date: Thu, 02 Dec 2021 03:24:14 GMT < content-type: text/html; charset=utf-8 < access-control-allow-origin: * < access-control-allow-credentials: true < content-length: 0 < x-envoy-upstream-service-time: 2 < hello: world! < * Connection #0 to host httpbin left intact
The header “hello: world!” is there from httpbin’s response. You won’t have to annotate the httpbin deployment with anything extra, nor will you need to redeploy anything. Check the Istiod log:
kubectl logs deploy/istiod -n istio-system
The push event to push the “helloworld” WasmPlugin configuration to Envoy Proxy is logged:
2021-12-02T03:22:36.776725Z info ads Push debounce stable[33] 1 for config WasmPlugin/default/helloworld: 101.0969ms since last change, 101.0917ms since last push, full=true
Check the httpbin’s istio-proxy log:
kubectl logs deploy/httpbin -c istio-proxy
You can see the add_header plugin from the helloworld WasmPlugin resource is executed in Envoy:
2021-12-02T03:22:38.046620Z warning envoy wasm wasm log add_header: returning context for add_header
Understanding Envoy configuration for the new WasmPlugin resource
Let’s obtain the listener configuration for httpbin for port 15006. You may be asking, why port 15006? By default, the Istio sidecar captures all inbound traffic and redirects it to port 15006 of the Istio proxy container.
istioctl pc listener deploy/httpbin --port 15006 -ojson | grep helloworld -A 11 -B 1
The output shows the virtualInbound listener on port 15006, with six occurrences of the helloworld http filters, each added to its filter chain:
{ "name": "default.helloworld", "configDiscovery": { "configSource": { "ads": {}, "initialFetchTimeout": "0s", "resourceApiVersion": "V3" }, "typeUrls": [ "type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm" ] } },
So, why are there six occurrences of these? Feel free to examine the output in detail to understand the filterchain, transport protocol, application protocol, or destination port that each filter chain matches.
Enable peer authentication policy for the default namespace:
cat peerauth.yaml apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata: name: default namespace: default spec: mtls: mode: STRICT kubectl apply -f peerauth.yaml peerauthentication.security.istio.io/default created
Obtain the listener configuration for httpbin for port 15006 again.
istioctl pc listener deploy/httpbin --port 15006 -ojson | grep helloworld -A 11 -B 1
You will only see three occurrences of the helloworld wasm httpfilter, which is easier for you to analyze the output. The reason for this is that after strict mutual TLS is enabled in the default namespace, the sidecar is configured to only allow the tls
transport protocol thus no need to have the filter chains for the raw_buffer
transport protocol, e.g. "transportProtocol": "raw_buffer"
.
The above example shows the most simple Wasm plugin you could build and apply to your services in the mesh with the newly-added WasmPlugin resource in Istio 1.12, without any need to patch or redeploy your service. The WasmPlugin resource contains rich configurations such as Wasm plugin injection phase in the filter chains and priorities within a given phase. While this example uses a Wasm OCI image built from Solo’s Gloo Mesh Open Source “meshctl wasm” CLI, you could also use Wasm compat images from Docker Hub using the docker or buildah CLI. Feel free to refer to Istio’s WasmPlugin resource for more details.
The future of Wasm
We are excited that our earlier vision around “WasmDeployment” has been shared across the Istio community, and the new WasmPlugin resource has now been developed and executed in Istio 1.12 through collaboration and hard work from many Istio contributors. We continue to believe Wasm will play a critical role for developers and operators to extend their data plane services and it’s great to see innovation across the open source ecosystem. We look forward to collaborating on future solutions to provide the simplest tooling and the best deployment experience for Wasm users. At Solo.io, we’re also continuing to drive development and improvements for customers using Wasm and provide common extension scenarios as formal APIs such as rate limiting or external auth.
To get involved with Wasm, join the discussion in the community slack or register for an upcoming event. Or if you’re ready to start building and sharing modules with the community, visit the WebAssembly Hub and tutorials in docs.