← Back to overview

Replicate Traefik Middleware Behavior in Envoy Gateway

When migrating from Traefik to Envoy Gateway, you might be used to apply Middleware manifests with Traefik for some standard fixtures as e.g. adding security-relevant headers to all responses, so the underlying application doesn’t have to take care of it.

In this post, I’m going over a few Middlewares I used with Traefik and how I replaced them after migrating to Envoy Gateway in my personal as well as in my company’s Kubernetes cluster. As Envoy Gateway doesn’t know the concept of standalone Middleware manifests, the majority of replacements are applied as BackendTrafficPolicy for a certain HTTPRoute, referencing them in the targetRefs field.

Response Compression

Traefik

With Traefik, you could simply add the compress field with an empty object to a Middleware manifest, effectively instructing Treafik to compress all responses to the requesting clients. This option could be fine-tuned to only compress responses of a certain Content-Type or of a certain size.

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: compress
spec:
compress: {}

Envoy Gateway

Unfortunately, Envoy Gateway doesn’t really support that many configuration possibilties, yet. When applying the BackendTrafficPolicy with an enabled compressor field, all requests towards the referenced targetRefs are affected from the response compression. The only way of applying the compression to only certain responses would be by specifying multiple HTTPRoutes and then only applying the BackendTrafficPolicy to those, who sould be compressed. That’s a bit cumbersome, but it follows the generic Gateway API approach and most likely won’t change over time.

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: my-httproute-btp
spec:
targetRefs:
- kind: HTTPRoute
group: gateway.networking.k8s.io
name: my-httproute
compressor:
- type: Brotli
brotli: {}

As with Traefik, instead of brotli, gzip and zstd can be used. As the compressor field is an array, you can specify multiple possible compression algorithms. Envoy Gateway will use the algorightm, preferred by the client and advertised via the Accept-Encoding header.

IP Whitelists

Traefik

IP whitelisting is a first-class citizen Middleware as well. Its definition is straightforward and only involves listing all CIDR ranges that are allowed to access an IngressRoute that incorporates the IP whitelisting middlware.

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: ip-whitelist
spec:
ipWhiteList:
sourceRange:
- 192.168.0.0/16
- 10.0.0.0/8
- 172.16.0.0/12

Envoy Gateway

In the world of Envoy Gateway and Kubernetes Gateway API, IP whitelisting is being done by creating a SecurityPolicy object, again referencing one or multiple HTTPRoutes the policy should be applied to. In contrast to Traefik, the logic of application is the other way around: Instead of defining within the routing object which middlewares should be applied, you now specify which routes a certain object should apply to, keeping the routes theirselves clean and simple and leveraging a separation of concerns when it comes to infrastructure and development teams.

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
name: my-httproute-sp
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: my-httproute
authorization:
defaultAction: Deny
rules:
- action: Allow
principal:
clientCIDRs:
- 192.168.0.0/16
- 10.0.0.0/8
- 172.16.0.0/12

A neat functionality of Envoy Proxy’s SecurityPolicy objects is that you can specify a defaultAction. That way you could turn the logic of the policy around, defaulting to allowing everything and then only denying access from certain IP addresses that are within that list.

Adding Security Headers to Responses

Traefik

The Middleware that was used with Traefik to add certain headers to a response (and stripping some of them) had some custom fields that allowed the operator to add certain security headers right away without typing out their exact names and contents.

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: security-headers
spec:
headers:
frameDeny: true
browserXssFilter: true
customResponseHeaders:
Server: ""

Envoy Gateway

With the Gateway API in Kubernetes, filters are a first-class citizen of the default implementation. One of these filters is a responseHeaderModified allowing you to set, add and remove certain headers from responses before they are being sent to the user.

Personally, I like this approach a bit more than a middleware specialised in adding three or four headers to every response. It allows for much more flexibility and is also useful for e.g. removing the Server header or other kinds of exposure of the software versions you’re using.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-route
spec:
parentRefs:
- kind: Gateway
group: gateway.networking.k8s.io
name: gateway
namespace: envoy-gateway-system
sectionName: https
hostnames:
- "example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: backend
port: 8000
filters:
- type: ResponseHeaderModifier
responseHeaderModifier:
set:
- name: "X-Frame-Options"
value: "DENY"
- name: "X-XSS-Protection"
value: "1; mode=block"
remove:
- "Server"

Max Request Size

Traefik

Within Traefik’s buffering field in the Middleware object, you can set the max size of an incoming request. Reuests larger than the defined value are being rejected with a HTTP 413 error.

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: max-request-size
spec:
buffering:
maxRequestBodyBytes: 20971520 # 20 MiB

Envoy Gateway

With Envoy Gateway that behavior is again being handled within the BackendTrafficPolicy. It can e.g. be added together with a response compression instruction.

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: my-httproute-btp
spec:
targetRefs:
- kind: HTTPRoute
group: gateway.networking.k8s.io
name: my-httproute
connection:
bufferLimit: 20Mi