Istio (envoy) rate limits for matching the absence of a header

Viewed 561

We'd like to implement envoyFilters that allow us to apply a local rate limit of 20 requests as maximum per minute to all traffic that has not a particular header. Idea is to limit the amount of request to all non-authenticated users which should lack the header x-user-auth: some_value.

All requests are done to the same Kubernetes service and from different/undetermined origins. We are not using any Istio ingressgateway, but all the pods that are part of the circuit of these requests have the Istio sidecar proxy injected into them.

How could this be achieved?

2 Answers

Looking over Envoy's Rate Limit Service documentation, there is no obvious way to limit request rates based on headers.

However, such configuration may be possible with Istio's Request Routing and Rate Limits.
Creating route based on user identity matching headers

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
...
spec:
  hosts:
  - foo
  http:
  - match:
    - headers:
        x-user-auth:
          exact: <some_value>
    route:
    - destination:
        host: foo
        subset: bar
  - route:
    - destination:
        host: foo
        subset: baz

and creating services with local rate limiting.

This configuration wil, hopefully, redirect requests with x-user-auth header to non-limited service (bar), and everyone else to a limited one (baz).

I'm not using the local rate limit, but external service that acts as our ratelimiter - I've described it in more details in this article: https://domagalski-j.medium.com/istio-rate-limits-for-egress-traffic-8697df490f68

So in my case it was just a matter of adjusting envoy actions. I've changed it from generic_key to request_headers - as you can read in the docs, request_headers have an option: skip_if_absent - if left blank then if a given header is not attached to the request, the request is not forwarded to rate limiter service. You are trying to ratelimit everything that doesn't have a particular header so maybe "header_value_match" action will suits you better, as it has "expect_match" field that you may use.

This is EnvoyFilter I've used in istio:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: route-httpbin
  namespace: default
spec:
  workloadSelector:
    labels:
      app: bastion-box
  configPatches:
    - applyTo: HTTP_ROUTE
      match:
        context: SIDECAR_OUTBOUND
        routeConfiguration:
          vhost:
            name: "httpbin.org:80"
            route:
              name: "default"
      patch:
        operation: MERGE
        value:
          route:
            rate_limits:
              - actions:
                  - request_headers:
                      header_name: "X-Client-Id"
                      descriptor_key: "clientId"
                  - request_headers:
                      header_name: "X-Credential-Username"
                      descriptor_key: "username"

I also found this article very helpful to understand envoy filters: https://www.aboutwayfair.com/tech-innovation/understanding-envoy-rate-limits

Related