/envoy-wasm-header-augmenting-filter

Proof of concept Envoy WASM-based HTTP filter that can augment requests with additional headers automatically discovered from a 3rd party endpoint at regular intervals.

Primary LanguageRust

envoy-wasm-header-augmenting-filter

Proof of concept Envoy WASM-based HTTP filter that can augment requests with additional headers automatically discovered from a 3rd party endpoint at regular intervals.

The header-providing 3rd party service can be any configured Envoy cluster. In an Istio context, this could be another sidecar available over loopback in the same pod, or some external centralised service perhaps in the mesh authorising based on SPIFFE identity, with circuit breakers, retries, load balancing and all the usual Istio Envoy goodness.

A potential use case of a filter like this would be to automatically gather and add IdP tokens to outbound requests on behalf of mesh workloads, to federate identity beyond the mesh itself.

Configuration

See envoy.yaml for a full example. Defaults:

{
    "header_providing_service_cluster": "sidecar",
    "header_providing_service_authority": "sidecar",
    "header_providing_service_path": "/headers",
    "header_cache_expiry": "360s"
}

The header-providing service is expected to return a simple JSON map of headers. These will all be added to HTTP requests passing through the filter.

The Envoy filter will poll the service using the header_providing_service_cluster at header_providing_service_path, presenting as header_providing_service_authority.

Valid headers returned from this service are cached by the Envoy filter, renewing every header_cache_expiry interval. This polling and caching action is happening out-of-band on the filter root context rather than the request path as the WASM workers process them.

Usage

There is a docker-compose.yaml stack for testing the filter locally and also a sample of how to deploy it to an Istio-enabled Kubernetes cluster (using a Kube ConfigMap to host the WASM binary and Istio’s EnvoyFilter combined with volume mount annotations to load it into the sidecar).

Building

Any sufficiently modern Rust toolchain wired with the WASM target should be able to compile the filter.

The shell.nix contains a Nix expression that when evaluated will give you a pure environment with everything you need. Lorri and direnv can additionally be used for caching.

A build target is available in the Makefile:

# Optionally: nix-shell --pure
# OR
# Optionally: direnv allow && lorri shell
make build

WIP

  • [X] TODO Test locally with a docker-compose stack emulating a pod with sidecars
  • [X] TODO Test remotely in an Istio-enabled Kube cluster
  • [-] TODO WASM binary size shrinking Attempt 1: 1.7mb –> 372kb with lto set to true and opt-level set to ‘s’ Attempt 2: 372kb –> 131kb with wasm-pack More than good enough for shipping to a binary Kube config map.