Working with EnvoyFilter
1. Understanding EnvoyFilter CRD
| Field | Description | Values |
|---|---|---|
| metadata.name | Name of the EnvoyFilter resource | string |
| metadata.namespace | Namespace where the EnvoyFilter is applied | string |
| spec.workloadSelector | Selects the workload(s) to apply this filter to | object |
| spec.filters | List of filters to apply to the Envoy configuration | array |
Example: Basic EnvoyFilter
apiVersion: networking.istio.io/v1beta1
kind: EnvoyFilter
metadata:
name: custom-filter
namespace: istio-system
spec:
workloadSelector:
labels:
app: frontend
filters:
- filterName: envoy.filters.http.router
filterType: HTTP
listenerMatch:
listenerType: SIDECAR_INBOUND
2. Creating EnvoyFilter Resources
EnvoyFilter resources are used to customize the configuration of Envoy proxies in a service mesh. They allow you to modify various aspects of the proxy's behavior, such as listeners, clusters, and filters.
| Field | Description | Example |
|---|---|---|
| metadata.name | Name of the EnvoyFilter resource | custom-filter |
| metadata.namespace | Namespace where the EnvoyFilter is applied | istio-system |
| spec.workloadSelector.labels | Labels to select the workload(s) to which the filter applies | {app: frontend} |
| spec.filters | List of filters to apply to the proxy configuration | [{name: router, type: HTTP_FILTER}] |
Example: Basic EnvoyFilter Definition
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: custom-filter
namespace: istio-system
spec:
workloadSelector:
labels:
app: frontend
filters:
- filterName: router
filterType: HTTP_FILTER
filterConfig:
statPrefix: custom-router
Note: The
workloadSelector is used to target specific workloads. If not specified, the filter will apply to all workloads in the namespace.
3. Configuring HTTP Connection Manager Filters
| Property | Description | Values | Notes |
|---|---|---|---|
| http_connection_manager | HTTP connection manager configuration | object |
Core configuration for HTTP handling in Envoy |
| http_filters | List of HTTP filters to apply | array |
Each filter is an object with name and config |
| access_log | Access log configuration | object |
Defines how and where to log HTTP traffic |
| stat_prefix | Prefix for statistics generated by the filter | string |
Used to namespace statistics in metrics |
Example: Basic HTTP Connection Manager Configuration
http_connection_manager:
stat_prefix: ingress_http
access_log:
- name: envoy.access_loggers.file
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: "/dev/stdout"
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
Example: Adding a Custom HTTP Filter
http_connection_manager:
stat_prefix: ingress_http
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- name: custom.http.filter
typed_config:
"@type": type.googleapis.com/custom.HttpFilterConfig
custom_param: "value"
4. Configuring Network Filters
| Filter | Description | Configuration | Notes |
|---|---|---|---|
| envoy.filters.listener.http_connection_manager | Manages HTTP connections and routing | { "http_filters": [...] } |
Core filter for HTTP traffic |
| envoy.filters.listener.tcp_proxy | Handles TCP traffic proxying | { "cluster": "tcp-cluster" } |
Used for TCP-based services |
| envoy.filters.listener.tls_inspector | Inspects TLS handshake for SNI and ALPN | {} |
Required for TLS-based routing |
| envoy.filters.listener.http_inspector | Inspects HTTP traffic for protocol detection | {} |
Used to detect HTTP/1.1 vs HTTP/2 |
Example: Configuring HTTP Connection Manager
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: http-connection-manager-filter
spec:
workloadSelector:
labels:
app: frontend
configPatches:
- applyTo: LISTENER
match:
context: SIDECAR_INBOUND
listener:
portNumber: 80
patch:
operation: MERGE
value:
listener_filters:
- name: envoy.filters.listener.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.http_connection_manager.v3.HttpConnectionManager
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
Example: Adding TCP Proxy Filter
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: tcp-proxy-filter
spec:
workloadSelector:
labels:
app: backend
configPatches:
- applyTo: LISTENER
match:
context: SIDECAR_INBOUND
listener:
portNumber: 9000
patch:
operation: MERGE
value:
listener_filters:
- name: envoy.filters.listener.tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tcp_proxy.v3.TcpProxy
cluster: tcp-cluster
5. Implementing Filter Patches
| Field | Description | Values | Notes |
|---|---|---|---|
| name | Name of the filter patch | string |
Unique identifier within the EnvoyFilter |
| match | Match criteria for applying the patch | object |
Defines where and when to apply the patch |
| patch | Configuration changes to apply | object |
Contains the actual patch operation details |
Example: Adding a Custom Filter
name: custom-filter-patch
match:
context: SIDECAR_INBOUND
listener:
portNumber: 8080
filterChain:
name: "envoy.http_connection_manager"
patch:
operation: INSERT_BEFORE
value:
name: custom-filter
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.custom.v3.CustomFilter
config:
custom_setting: "value"
Example: Modifying Existing Filter Configuration
name: modify-filter-config
match:
context: SIDECAR_OUTBOUND
routeConfiguration:
name: "route-config"
patch:
operation: MERGE
value:
virtual_hosts:
- name: "modified-host"
domains:
- "example.com"
Note: The
operation field supports ADD, REPLACE, REMOVE, INSERT_BEFORE, and INSERT_AFTER.
Warning: Incorrect patch operations can break service mesh functionality. Always test in a staging environment.
6. Managing Filter Priority
| Priority Level | Description | Usage |
|---|---|---|
| 0 | Lowest priority, applied last | For non-critical filters that should not interfere with core functionality |
| 100 | Standard priority, applied after low-priority filters | Default for most custom filters |
| 500 | High priority, applied before core filters | For filters that must run early in the filter chain |
| 1000 | Highest priority, applied first | For critical filters that must run before any other |
Example: Setting Filter Priority in EnvoyFilter
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: custom-filter
spec:
filters:
- filterName: envoy.filters.http.router
filterType: HTTP
priority: 500
Note: Priority levels are relative to other filters in the same
EnvoyFilter and can be overridden by filterChain settings.7. Configuring Listener Filters
| Property | Description | Values | Notes |
|---|---|---|---|
| listener_filters | List of listener filters to apply | ["tcp_proxy", "http_connection_manager"] |
Filters applied to the listener in order of definition |
| name | Name of the listener filter | "tcp_proxy" |
Must match a known filter name in Envoy |
| typed_config | Configuration for the listener filter | {...} |
JSON configuration object for the filter |
Example: Configuring TCP Proxy Listener Filter
listener_filters:
- name: tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tcp_proxy.v3.TcpProxy
cluster: "tcp-cluster"
idle_timeout: "30s"
Note: Listener filters are applied to the listener before any connection is established. They can modify or inspect traffic at the listener level.
8. Setting EnvoyFilter Scope
| Scope | Description | Applicable Resources | Notes |
|---|---|---|---|
| cluster | Applies filter to a specific cluster | Cluster |
Used for modifying traffic behavior to a specific destination |
| listener | Applies filter to a listener | Listener |
Can modify how traffic is received or forwarded at the listener level |
| route | Applies filter to a specific route within a VirtualHost | Route |
Allows fine-grained control over routing decisions and headers |
| virtualHost | Applies filter to a VirtualHost | VirtualHost |
Useful for applying filters to all routes within a host |
| gateway | Applies filter to a gateway | Gateway |
Applies to traffic entering or exiting a gateway |
Example: Setting EnvoyFilter Scope to Listener
apiVersion: networking.istio.io/v1beta1
kind: EnvoyFilter
metadata:
name: listener-filter
spec:
configPatches:
- applyTo: LISTENER
match:
context: SIDECAR_INBOUND
listener:
portNumber: 8080
name: "inbound|8080"
patch:
operation: MERGE
value:
listener_filters:
- name: envoy.listener.http_inspector
9. Implementing Rate Limit Filters
| Property | Description | Values | Notes |
|---|---|---|---|
| rateLimit | Rate limit configuration | {} |
Defines rate limiting rules for traffic |
| rateLimit.requestsPerUnit | Number of requests allowed per time unit | 10 |
Default is 10 requests per unit |
| rateLimit.unit | Time unit for rate limiting | MINUTE, HOUR, DAY |
Valid values are MINUTE, HOUR, DAY |
| rateLimit.duration | Duration of rate limit period | 60 |
Duration in seconds (default 60) |
Example: Rate Limit Configuration
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: rate-limit-filter
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
name: "inbound|8080"
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.local_ratelimit
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
stat_prefix: "http_local_rate_limit"
token_bucket:
max_tokens: 100
tokens_per_fill: 50
fill_interval: 60s
Note: Rate limiting can be applied to inbound or outbound traffic depending on the context.
Warning: Ensure that rate limits do not block legitimate traffic or cause service degradation.
| Rate Limit Type | Description | Use Case | Notes |
|---|---|---|---|
| Local Rate Limit | Rate limiting within a single Envoy instance | Per-pod or per-instance limits | Does not scale across multiple instances |
| Global Rate Limit | Rate limiting across multiple Envoy instances | Cluster-wide or service-wide limits | Requires external rate limiting service (e.g., Redis, Google Cloud) |
10. Troubleshooting EnvoyFilter Issues
Example: Checking EnvoyFilter Application Status
apiVersion: networking.istio.io/v1beta1
kind: EnvoyFilter
metadata:
name: example-filter
namespace: istio-system
spec:
workloadSelector:
labels:
app: example-app
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
portNumber: 15006
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.router
| Issue | Description | Solution |
|---|---|---|
| Filter Not Applied | EnvoyFilter not applied to the target workload | Verify workloadSelector matches workload labels |
| Incorrect Patch Operation | Using wrong operation (e.g., ADD instead of REPLACE) |
Use correct operation for desired modification |
| Port Mismatch | Specified port does not match actual listener port | Check listener.portNumber matches the target port |
| Context Mismatch | Applying filter to wrong context (e.g., SIDECAR_INBOUND when it should be GATEWAY) |
Ensure context matches the intended proxy type |
Note: Use
istioctl proxy-config to inspect the actual configuration applied to a proxy.Workflow: Debugging EnvoyFilter Application
- Verify
workloadSelectormatches labels of target pods - Check that
portNumberinlistenermatches actual port used by the proxy - Confirm
contextis appropriate for the proxy type (inbound, outbound, gateway) - Use
istioctl proxy-configto inspect actual configuration applied - Review logs from
istiodfor EnvoyFilter application errors
11. Implementing Custom Header Filters
| Property | Description | Example |
|---|---|---|
| header.name | Name of the header to filter | X-Custom-Header |
| header.value | Value to match or set for the header | custom-value |
| header.operation | Operation to perform on the header (add, remove, replace) | add |
Example: Adding a Custom Header
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: custom-header-filter
spec:
filters:
- filterChain:
- listenerName: "http"
filterName: "envoy.http_connection_manager"
filterType: "HTTP"
insert:
- name: "envoy.filters.http.header_to_metadata"
typedConfig:
"@type": "type.googleapis.com/envoy.extensions.filters.http.header_to_metadata.v3.Config"
requestHeadersToAdd:
- header:
name: "X-Custom-Header"
value: "custom-value"
Example: Removing a Header
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: remove-header-filter
spec:
filters:
- filterChain:
- listenerName: "http"
filterName: "envoy.http_connection_manager"
filterType: "HTTP"
insert:
- name: "envoy.filters.http.router"
typedConfig:
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
dynamicStats: "true"
12. Managing EnvoyFilter Versioning
| Version | Changes | Notes |
|---|---|---|
| v1alpha3 | EnvoyFilter in istio.io/api |
Initial stable version with full support for Envoy configuration |
| v1beta1 | Updated schema with listener_filters, network_filters |
Enhanced filter support; backward compatible with v1alpha3 |
| v1 | NEW filter_chains, http_filters |
Major update with improved configuration structure and new filter types |
Example: Applying EnvoyFilter v1
apiVersion: networking.istio.io/v1
kind: EnvoyFilter
metadata:
name: custom-filter
spec:
workloadSelector:
labels:
app: frontend
config:
http_filters:
- name: custom-filter
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.custom.v1.CustomFilter
config:
param1: value1
Note: Ensure all
EnvoyFilter resources are validated against the target Istio version to avoid runtime errors.