Extensions

You can use WebAssembly extensions to add new features directly into the Maistra Service Mesh proxies, allowing you to move even more common functionality out of your applications, and implement them in a single language that compiles to WebAssembly bytecode.

WebAssembly extensions

WebAssembly modules can be run on many platforms, including proxies, and has broad language support, fast execution and a sandboxed-by-default security model.

Extension Capabilities

Maistra Service Mesh extensions are Envoy HTTP Filters, giving them a wide range of capabilities:

  • Manipulating the body and headers of requests and responses

  • Out-of-band HTTP requests to services not in the request path, such as authentication or policy checking

  • Side-channel data storage and queues for filters to communicate with each other

There are two parts to writing a Maistra Service Mesh extension: you’ll have to write your extension using an SDK that exposes the proxy-wasm API and compile it to a WebAssembly module, and then package it into a container.

Supported languages

You can use any language that compiles to WebAssembly bytecode to write a Maistra Service Mesh extension, but the following languages have existing SDKs that expose the proxy-wasm API so that it can be consumed directly.

Table 1. Supported languages
Language Maintainer Repository

AssemblyScript

solo.io

solo-io/proxy-runtime

C++

proxy-wasm team (Istio Community)

proxy-wasm/proxy-wasm-cpp-sdk

Go

tetrate.io

tetratelabs/proxy-wasm-go-sdk

Rust

proxy-wasm team (Istio Community)

proxy-wasm/proxy-wasm-rust-sdk

Container Format

You must have a .wasm file containing the bytecode of your WebAssembly module, and a manifest.yaml file in the root of the container filesystem to make your container image a valid extension image.

manifest.yaml
schemaVersion: 1

name: <your-extension>
description: <description>
version: 1.0.0
phase: PreAuthZ
priority: 100
module: extension.wasm
Table 2. Field Reference for manifest.yml
Field Description

schemaVersion

Used for versioning of the manifest schema. Currently the only possible value is 1.

name

The name of your extension. This field is just metadata and currently unused.

description

The description of your extension. This field is just metadata and currently unused.

version

The version of your extension. This field is just metadata and currently unused.

phase

The default execution phase of your extension. This is a required field.

priority

The default priority of your extension. This is a required field.

module

The relative path from the container filesystem’s root to your WebAssembly module. This is a required field.

Example Rust extension

For a complete example that was built using the Rust SDK, take a look at the header-append-filter. It is a simple filter that appends one or more headers to the HTTP responses, with their names and values taken out from the config field of the extension. See a sample configuration in the snippet below.

Deploying extensions

Maistra Service Mesh extensions can be enabled using the ServiceMeshExtension resource. In this example, istio-system is the name of the control plane project.

Procedure
  1. Create the following example resource:

    Example ServiceMeshExtension resource extension.yaml
    apiVersion: maistra.io/v1
    kind: ServiceMeshExtension
    metadata:
      name: header-append
      namespace: istio-system
    spec:
      workloadSelector:
        labels:
          app: httpbin
      config:
        first-header: some-value
        another-header: another-value
      image: quay.io/maistra-dev/header-append-filter:2.1
      phase: PostAuthZ
      priority: 100
  2. Apply the extension.yaml file with the following command:

    $ oc apply -f extension.yaml
Table 3. ServiceMeshExtension Field Reference
Field Description

metadata.namespace

The metadata.namespace of a ServiceMeshExtension source has a special semantic: if it equals the Control Plane Namespace, the extension will be applied to all workloads in the Service Mesh that match its workloadSelector. When deployed to any other Mesh Namespace, it will only be applied to workloads in that same Namespace.

spec.workloadSelector

The spec.workloadSelector field has the same semantic as the spec.selector field of the Istio Gateway resource. It will match a workload based on its Pod labels. If no workloadSelector is specified, the extension will be applied to all workloads in the namespace.

spec.config

This is a structured field that will be handed over to the extension, with the semantics dependent on the extension you are deploying.

spec.image

A container image URI pointing to the image that holds the extension.

spec.phase

This field defaults to the value set in the manifest.yaml of the extension, but can be overwritten by the user. The phase determines where in the filter chain the extension is injected, in relation to existing Istio functionality like Authentication, Authorization and metrics generation. Valid values are: PreAuthN, PostAuthN, PreAuthZ, PostAuthZ, PreStats, PostStats. This field defaults to the value set in the manifest.yaml of the extension, but can be overwritten by the user.

spec.priority

If multiple extensions with the same spec.phase are applied to the same workload instance, the spec.priority determines the ordering of execution. Extensions with higher priority will be executed first. This allows for inter-dependent extensions. This field defaults to the value set in the manifest.yaml of the extension, but can be overwritten by the user.