Envoy Envoy

Configura filtros Envoy en bruto en Istio con EnvoyFilter

Para las funciones que las propias APIs de Istio no exponen, EnvoyFilter modifica directamente la configuración subyacente de Envoy, con cuidado.

14 min Avanzado

Los recursos de alto nivel de Istio, VirtualService, DestinationRule, AuthorizationPolicy, cubren la mayor parte de la gestión de tráfico del día a día sin que nadie necesite conocer directamente el formato de configuración de Envoy. Pero Envoy tiene muchos más filtros y opciones de los que expone cualquiera de esos recursos, y para ese hueco Istio ofrece EnvoyFilter: un recurso que modifica directamente la configuración de Envoy que genera Istio. Es una auténtica vía de escape, igual de potente que fácil de configurar mal, y esta guía cubre cómo está estructurado, con un ejemplo completo.

Para qué sirve EnvoyFilter

Si lo que necesitas tiene un recurso de Istio dedicado, una regla de enrutamiento, una política de reintentos, ajustes de TLS mutuo, usa ese recurso. EnvoyFilter existe para todo lo demás: filtros como scripting en Lua, request tapping, IP tagging o cualquier otra capacidad de Envoy para la que las APIs de más alto nivel de Istio simplemente no tienen un campo. Recurre a él solo cuando hayas confirmado que lo que necesitas realmente no se puede expresar con los recursos normales, ya que cada EnvoyFilter que añades es una cosa más que mantener sincronizada con la evolución de la propia configuración generada por Istio entre actualizaciones.

Las cuatro preguntas que responde todo EnvoyFilter

Todo recurso EnvoyFilter, sea lo que sea lo que configure, responde a las mismas cuatro preguntas:

  1. ¿A qué proxies se aplica? Un workloadSelector apunta a cargas de trabajo concretas por etiqueta; omitirlo aplica el parche a todo el namespace, o a toda la malla si se coloca en el namespace raíz/de configuración de Istio.
  2. ¿En qué parte de la configuración de Envoy se aplica el parche? El campo applyTo nombra el destino: LISTENER, FILTER_CHAIN, HTTP_FILTER, NETWORK_FILTER, CLUSTER, ROUTE_CONFIGURATION y unos cuantos más.
  3. Más concretamente, ¿qué instancia de eso? Un bloque match lo acota todavía más, por ejemplo un puerto de listener concreto, una cadena de filtros concreta, o si se aplica al tráfico entrante del sidecar, al saliente o a un gateway.
  4. ¿Qué operación debe realizarse y con qué contenido? El bloque patch especifica tanto una operación, ADD, REMOVE, MERGE, INSERT_BEFORE, INSERT_AFTER o INSERT_FIRST, como, para cualquier cosa que inserte o fusione configuración, la configuración real del filtro como su value.

Los cambios sensibles al orden (insertar un filtro HTTP en un punto concreto de la cadena) usan las operaciones INSERT_* y apuntan a un vecino con nombre, normalmente el filtro terminal envoy.filters.http.router, para decir “antes de este” o “después de este”.

Un ejemplo completo: etiquetar peticiones por IP

Esto añade el filtro HTTP ip_tagging al tráfico entrante del sidecar en el puerto 80, insertado justo antes del filtro router terminal:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ip-tagging
  namespace: default
spec:
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        listener:
          portNumber: 80
          filterChain:
            filter:
              name: envoy.filters.network.http_connection_manager
              subFilter:
                name: envoy.filters.http.router
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.ip_tagging
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.ip_tagging.v3.IPTagging
            request_type: BOTH
            ip_tags:
              - ip_tag_name: hello-envoy-conf
                ip_list:
                  - address_prefix: "0.0.0.0"
                    prefix_len: 0

Léelo de arriba abajo: sin workloadSelector, esto se aplica a todas las cargas de trabajo del namespace default. applyTo: HTTP_FILTER dice que estamos añadiendo un filtro HTTP. El bloque match lo acota al tráfico entrante del sidecar, en el listener enlazado al puerto 80, específicamente dentro de la cadena de filtros del HTTP Connection Manager, posicionado respecto al filtro router. El patch dice que se inserte un nuevo filtro antes de ese router, y da su configuración completa: el nombre del filtro, su type URL (@type) y los campos específicos del filtro, aquí, etiquetar cada petición con X-Envoy-IP-Tags: hello-envoy-conf sin importar la IP de origen (0.0.0.0/0 coincide con todo).

Aplícalo y confírmalo:

kubectl apply -f ip-tagging-filter.yaml
kubectl exec deploy/httpbin -c istio-proxy -- curl -s -D - http://localhost:80/get -o /dev/null | grep -i x-envoy-ip-tags

Encontrar el nombre, el type URL y los campos de un filtro

El name, el @type de typed_config y los campos que van debajo son específicos de cada filtro, y la propia documentación de filtros de Envoy es de donde salen, aunque está repartida en varias páginas enlazadas en lugar de estar en un solo lugar: la página de resumen de un filtro normalmente enlaza a su referencia de protobuf, que a su vez define cada campo, a menudo con más enlaces para los tipos anidados. Cuenta con bastante cambio de pestañas. Algunas cosas lo agilizan:

  • Busca el type URL en GitHub una vez que lo tengas. Para cualquier filtro razonablemente común, alguien probablemente ya haya publicado un EnvoyFilter o una configuración de Envoy en bruto que lo usa y funciona, lo que suele ser un punto de partida más rápido que armar uno solo a partir de la referencia de campos.
  • No todos los filtros de Envoy están compilados en el build de proxy de Istio. Istio distribuye un build concreto de Envoy, y un filtro documentado en envoyproxy.io no está garantizado que esté incluido en él. Confirma que un filtro está realmente disponible en el build de Istio antes de diseñar una solución en torno a él.
  • Usa JSON en lugar de YAML para el bloque value si te resulta propenso a errores la indentación de YAML para configuraciones muy anidadas; la configuración de Envoy acepta ambos, y una indentación mal colocada en un bloque YAML anidado es una de las formas más habituales de que un EnvoyFilter falle en silencio y no haga lo que pretendías.

Inspeccionar lo que realmente se está ejecutando

Dos herramientas ayudan a confirmar que un parche aterrizó como esperas, en lugar de adivinarlo solo por el comportamiento:

istioctl proxy-config listener POD_NAME -n NAMESPACE
istioctl proxy-config route POD_NAME -n NAMESPACE
istioctl proxy-config cluster POD_NAME -n NAMESPACE
istioctl proxy-config all POD_NAME -n NAMESPACE -o json

istioctl proxy-config, seguido de bootstrap, clusters, routes, listeners o all, imprime la configuración real de un sidecar dado tal como la han ensamblado Istio y Envoy, como tabla por defecto o como YAML/JSON con -o. Esta es la verdad de base sobre lo que realmente se está ejecutando, a diferencia de lo que pretendías parchear. Para comparar visualmente un volcado completo de configuración, una configuración completa de Envoy es más de lo que la mayoría quiere leer directamente en una terminal; un visor de volcados de configuración que la muestre como una estructura navegable y con enlaces cruzados (la comunidad de Envoy mantiene algunos) suele ser más fácil de recorrer que desplazarse por JSON en bruto.

La advertencia principal

EnvoyFilter parchea configuración que el propio Istio genera y regenera con cada cambio, lo que significa que está intrínsecamente acoplado a los internos de Istio de una manera que los recursos de más alto nivel no lo están. Un EnvoyFilter escrito para una versión de Istio puede dejar de coincidir con nada en silencio, o coincidir con algo no previsto, después de una actualización que cambie cómo Istio estructura sus listeners o cadenas de filtros generados. Trátalo como sugiere su nombre: una herramienta precisa para un hueco específico y verificado, probada tras cada actualización de Istio, no una forma predeterminada de configurar el tráfico.

Guías populares