Envoy Filter
EnvoyFilter
provides a mechanism to customize the Envoy
configuration generated by Istio Pilot. Use EnvoyFilter to modify
values for certain fields, add specific filters, or even add
entirely new listeners, clusters, etc. This feature must be used
with care, as incorrect configurations could potentially
destabilize the entire mesh. Unlike other Istio networking objects,
EnvoyFilters are additively applied. Any number of EnvoyFilters can
exist for a given workload in a specific namespace. The order of
application of these EnvoyFilters is as follows: all EnvoyFilters
in the config root
namespace,
followed by all matching EnvoyFilters in the workload’s namespace.
NOTE 1: Some aspects of this API are deeply tied to the internal implementation in Istio networking subsystem as well as Envoy’s XDS API. While the EnvoyFilter API by itself will maintain backward compatibility, any envoy configuration provided through this mechanism should be carefully monitored across Istio proxy version upgrades, to ensure that deprecated fields are removed and replaced appropriately.
NOTE 2: When multiple EnvoyFilters are bound to the same workload in a given namespace, all patches will be processed sequentially in order of creation time. The behavior is undefined if multiple EnvoyFilter configurations conflict with each other.
NOTE 3: To apply an EnvoyFilter resource to all workloads (sidecars and gateways) in the system, define the resource in the config root namespace, without a workloadSelector.
The example below declares a global default EnvoyFilter resource in
the root namespace called istio-config
, that adds a custom
protocol filter on all sidecars in the system, for outbound port
9307. The filter should be added before the terminating tcp_proxy
filter to take effect. In addition, it sets a 30s idle timeout for
all HTTP connections in both gateways and sidecars.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: custom-protocol
namespace: istio-config # as defined in meshConfig resource.
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
context: SIDECAR_OUTBOUND # will match outbound listeners in all sidecars
listener:
portNumber: 9307
filterChain:
filter:
name: "envoy.filters.network.tcp_proxy"
patch:
operation: INSERT_BEFORE
value:
# This is the full filter config including the name and typed_config section.
name: "envoy.extensions.filters.network.mongo_proxy"
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.mongo_proxy.v3.MongoProxy"
...
- applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
match:
# context omitted so that this applies to both sidecars and gateways
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: MERGE
value:
name: "envoy.filters.network.http_connection_manager"
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
common_http_protocol_options:
idle_timeout: 30s
The following example enables Envoy’s Lua filter for all inbound HTTP calls arriving at service port 8080 of the reviews service pod with labels “app: reviews”, in the bookinfo namespace. The lua filter calls out to an external service internal.org.net:8888 that requires a special cluster definition in envoy. The cluster is also added to the sidecar as part of this configuration.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: reviews-lua
namespace: bookinfo
spec:
workloadSelector:
labels:
app: reviews
configPatches:
# The first patch adds the lua filter to the listener/http connection manager
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
portNumber: 8080
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value: # lua filter specification
name: envoy.filters.http.lua
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
defaultSourceCode:
inlineString: |
function envoy_on_request(request_handle)
-- Make an HTTP call to an upstream host with the following headers, body, and timeout.
local headers, body = request_handle:httpCall(
"lua_cluster",
{
[":method"] = "POST",
[":path"] = "/acl",
[":authority"] = "internal.org.net"
},
"authorize call",
5000)
end
# The second patch adds the cluster that is referenced by the lua code
# cds match is omitted as a new cluster is being added
- applyTo: CLUSTER
match:
context: SIDECAR_OUTBOUND
patch:
operation: ADD
value: # cluster specification
name: "lua_cluster"
type: STRICT_DNS
connect_timeout: 0.5s
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: lua_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
protocol: TCP
address: "internal.org.net"
port_value: 8888
The following example overwrites certain fields (HTTP idle timeout and X-Forward-For trusted hops) in the HTTP connection manager in a listener on the ingress gateway in istio-system namespace for the SNI host app.example.com:
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: hcm-tweaks
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
match:
context: GATEWAY
listener:
filterChain:
sni: app.example.com
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: MERGE
value:
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
xff_num_trusted_hops: 5
common_http_protocol_options:
idle_timeout: 30s
The following example inserts an attributegen filter
that produces istio_operationId
attribute which is consumed
by the istio.stats filter. filterClass: STATS
encodes this dependency.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: reviews-request-operation
namespace: myns
spec:
workloadSelector:
labels:
app: reviews
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
patch:
operation: ADD
filterClass: STATS # This filter will run *before* the Istio stats filter.
value:
name: istio.request_operation
typed_config:
"@type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
value:
config:
configuration: |
{
"attributes": [
{
"output_attribute": "istio_operationId",
"match": [
{
"value": "ListReviews",
"condition": "request.url_path == '/reviews' && request.method == 'GET'"
}]
}]
}
vm_config:
runtime: envoy.wasm.runtime.null
code:
local: { inline_string: "envoy.wasm.attributegen" }
The following example inserts an http ext_authz filter in the myns
namespace.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: myns-ext-authz
namespace: myns
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
patch:
operation: ADD
filterClass: AUTHZ # This filter will run *after* the Istio authz filter.
value:
name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
grpc_service:
envoy_grpc:
cluster_name: acme-ext-authz
initial_metadata:
- key: foo
value: myauth.acme # required by local ext auth server.
A workload in the myns
namespace needs to access a different ext_auth server
that does not accept initial metadata. Since proto merge cannot remove fields, the
following configuration uses the REPLACE
operation. If you do not need to inherit
fields, REPLACE is preferred over MERGE.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: mysvc-ext-authz
namespace: myns
spec:
workloadSelector:
labels:
app: mysvc
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
patch:
operation: REPLACE
value:
name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
grpc_service:
envoy_grpc:
cluster_name: acme-ext-authz-alt
The following example deploys a Wasm extension for all inbound sidecar HTTP requests.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: wasm-example
namespace: myns
spec:
configPatches:
# The first patch defines a named Wasm extension and provides a URL to fetch Wasm binary from,
# and the binary configuration. It should come before the next patch that applies it.
# This resource is visible to all proxies in the namespace "myns". It is possible to provide
# multiple definitions for the same name "my-wasm-extension" in multiple namespaces. We recommend that:
# - if overriding is desired, then the root level definition can be overriden per namespace with REPLACE.
# - if overriding is not desired, then the name should be qualified with the namespace "myns/my-wasm-extension",
# to avoid accidental name collisions.
- applyTo: EXTENSION_CONFIG
patch:
operation: ADD # REPLACE is also supported, and would override a cluster level resource with the same name.
value:
name: my-wasm-extension
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
config:
root_id: my-wasm-root-id
vm_config:
vm_id: my-wasm-vm-id
runtime: envoy.wasm.runtime.v8
code:
remote:
http_uri:
uri: http://my-wasm-binary-uri
configuration:
"@type": "type.googleapis.com/google.protobuf.StringValue"
value: |
{}
# The second patch instructs to apply the above Wasm filter to the listener/http connection manager.
- applyTo: HTTP_FILTER
match:
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
subFilter:
name: envoy.filters.http.router
patch:
operation: INSERT_BEFORE
value:
name: my-wasm-extension # This must match the name above
config_discovery:
config_source:
ads: {}
type_urls: ["type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm"]
The following example adds a Wasm service extension for all proxies using a locally available Wasm file. The singleton Wasm extension is used to maintain a shared state between workers executing Wasm filters. For example, a local rate limit extension would rely on a singleton to limit requests across all workers. As another example, an authorization Wasm extension can use a singleton to maintain a database of accounts.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: wasm-service
namespace: myns
spec:
configPatches:
- applyTo: BOOTSTRAP
patch:
operation: MERGE
value:
bootstrap_extensions:
- name: envoy.bootstrap.wasm
typed_config:
"@type": type.googleapis.com/envoy.extensions.wasm.v3.WasmService
singleton: true
config:
name: my_plugin
configuration:
"@type": type.googleapis.com/google.protobuf.StringValue
value: |
{}
vm_config:
runtime: "envoy.wasm.runtime.v8"
code:
local:
filename: "/etc/envoy_filter_http_wasm_example.wasm"
The following example inserts an envoy.filters.listener.proxy_protocol
listener filter before the envoy.filters.listener.tls_inspector
.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: listener-filter-example
namespace: myns
spec:
configPatches:
- applyTo: LISTENER_FILTER
match:
context: SIDECAR_INBOUND # will match outbound listeners in all sidecars
listener:
portNumber: 15006
listenerFilter: "envoy.filters.listener.tls_inspector"
patch:
operation: INSERT_BEFORE
value:
# This is the full filter config including the name and typed_config section.
name: "envoy.filters.listener.proxy_protocol"
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.listener.proxy_protocol.v3.ProxyProtocol"
EnvoyFilter
EnvoyFilter provides a mechanism to customize the Envoy configuration generated by Istio Pilot.
EnvoyFilter.ProxyMatch
One or more properties of the proxy to match on.
EnvoyFilter.ClusterMatch
Conditions specified in ClusterMatch
must be met for the patch
to be applied to a cluster.
EnvoyFilter.RouteConfigurationMatch
Conditions specified in RouteConfigurationMatch must be met for the patch to be applied to a route configuration object or a specific virtual host within the route configuration.
EnvoyFilter.ListenerMatch
Conditions specified in a listener match must be met for the patch to be applied to a specific listener across all filter chains, or a specific filter chain inside the listener.
EnvoyFilter.Patch
Patch specifies how the selected object should be modified.
EnvoyFilter.EnvoyConfigObjectMatch
One or more match conditions to be met before a patch is applied to the generated configuration for a given proxy.
EnvoyFilter.EnvoyConfigObjectPatch
Changes to be made to various envoy config objects.
EnvoyFilter.RouteConfigurationMatch.RouteMatch
Match a specific route inside a virtual host in a route configuration.
EnvoyFilter.RouteConfigurationMatch.VirtualHostMatch
Match a specific virtual host inside a route configuration.
EnvoyFilter.ListenerMatch.FilterChainMatch
For listeners with multiple filter chains (e.g., inbound listeners on sidecars with permissive mTLS, gateway listeners with multiple SNI matches), the filter chain match can be used to select a specific filter chain to patch.
EnvoyFilter.ListenerMatch.FilterMatch
Conditions to match a specific filter within a filter chain.
EnvoyFilter.ListenerMatch.SubFilterMatch
Conditions to match a specific filter within another
filter. This field is typically useful to match a HTTP filter
inside the envoy.filters.network.http_connection_manager
network filter.
This could also be applicable for thrift filters.
EnvoyFilter.RouteConfigurationMatch.RouteMatch.Action
Action refers to the route action taken by Envoy when a http route matches.
Name | Description |
---|---|
ANY | All three route actions |
ROUTE | Route traffic to a cluster / weighted clusters. |
REDIRECT | Redirect request. |
DIRECT_RESPONSE | directly respond to a request with specific payload. |
EnvoyFilter.Patch.Operation
Operation denotes how the patch should be applied to the selected configuration.
Name | Description |
---|---|
INVALID | |
MERGE | Merge the provided config with the generated config using
proto merge semantics. If you are specifying config in its
entirety, use |
ADD | Add the provided config to an existing list (of listeners,
clusters, virtual hosts, network filters, or http
filters). This operation will be ignored when |
REMOVE | Remove the selected object from the list (of listeners,
clusters, virtual hosts, network filters, routes, or http
filters). Does not require a value to be specified. This
operation will be ignored when |
INSERT_BEFORE | Insert operation on an array of named objects. This operation is typically useful only in the context of filters or routes, where the order of elements matter. Routes should be ordered based on most to least specific matching criteria since the first matching element is selected. For clusters and virtual hosts, order of the element in the array does not matter. Insert before the selected filter or sub filter. If no filter is selected, the specified filter will be inserted at the front of the list. |
INSERT_AFTER | Insert operation on an array of named objects. This operation is typically useful only in the context of filters or routes, where the order of elements matter. Routes should be ordered based on most to least specific matching criteria since the first matching element is selected. For clusters and virtual hosts, order of the element in the array does not matter. Insert after the selected filter or sub filter. If no filter is selected, the specified filter will be inserted at the end of the list. |
INSERT_FIRST | Insert operation on an array of named objects. This operation is typically useful only in the context of filters or routes, where the order of elements matter. Routes should be ordered based on most to least specific matching criteria since the first matching element is selected. For clusters and virtual hosts, order of the element in the array does not matter. Insert first in the list based on the presence of selected filter or not. This is specifically useful when you want your filter first in the list based on a match condition specified in Match clause. |
REPLACE | Replace contents of a named filter with new contents.
|
EnvoyFilter.Patch.FilterClass
FilterClass determines the filter insertion point in the filter chain
relative to the filters implicitly inserted by the control plane.
It is used in conjuction with the ADD
operation.
This is the preferred insertion mechanism for adding filters over
the INSERT_*
operations since those operations rely on potentially unstable
filter names.
Filter ordering is important if your filter depends on or affects the
functioning of a another filter in the filter chain.
Within a filter class, filters are inserted in the order of processing.
Name | Description |
---|---|
UNSPECIFIED | Control plane decides where to insert the filter.
Do not specify |
AUTHN | Insert filter after Istio authentication filters. |
AUTHZ | Insert filter after Istio authorization filters. |
STATS | Insert filter before Istio stats filters. |
EnvoyFilter.ApplyTo
ApplyTo
specifies where in the Envoy configuration, the given patch should be applied.
Name | Description |
---|---|
INVALID | |
LISTENER | Applies the patch to the listener. |
FILTER_CHAIN | Applies the patch to the filter chain. |
NETWORK_FILTER | Applies the patch to the network filter chain, to modify an existing filter or add a new filter. |
HTTP_FILTER | Applies the patch to the HTTP filter chain in the http connection manager, to modify an existing filter or add a new filter. |
ROUTE_CONFIGURATION | Applies the patch to the Route configuration (rds output)
inside a HTTP connection manager. This does not apply to the
virtual host. Currently, only |
VIRTUAL_HOST | Applies the patch to a virtual host inside a route configuration. |
HTTP_ROUTE | Applies the patch to a route object inside the matched virtual host in a route configuration. |
CLUSTER | Applies the patch to a cluster in a CDS output. Also used to add new clusters. |
EXTENSION_CONFIG | Applies the patch to or adds an extension config in ECDS output. Note that ECDS is only supported by HTTP filters. |
BOOTSTRAP | Applies the patch to bootstrap configuration. |
LISTENER_FILTER | Applies the patch to the listener filter. |
EnvoyFilter.PatchContext
PatchContext selects a class of configurations based on the traffic flow direction and workload type.
Name | Description |
---|---|
ANY | All listeners/routes/clusters in both sidecars and gateways. |
SIDECAR_INBOUND | Inbound listener/route/cluster in sidecar. |
SIDECAR_OUTBOUND | Outbound listener/route/cluster in sidecar. |
GATEWAY | Gateway listener/route/cluster. |