Proxy Template
The proxy template provides configuration options for low-level Envoy resources that Kuma policies do not directly expose.
If you need features that aren’t available as a Kuma policy, open a new issue on GitHub so they can be added to the Kuma roadmap.
A ProxyTemplate policy can provide custom definitions of:
The custom definitions either complement or replace the resources that Kuma generates automatically.
Usage
Kuma uses the following default ProxyTemplate resource for every data plane proxy (kuma-dp) that is added to a Mesh. This resource looks like:
apiVersion: kuma.io/v1alpha1kind: ProxyTemplatemesh: defaultmetadata:name: custom-template-1spec:selectors:- match:kuma.io/service: '*'conf:# `imports` allows us to reuse the dataplane configuration that Kuma# generates automatically and add more customizations on top of itimports:# `default-proxy` is a reference name for the default# data plane proxy configuration generated by Kuma- default-proxy
type: ProxyTemplatemesh: defaultname: custom-template-1selectors:- match:kuma.io/service: '*'conf:# `imports` allows us to reuse the dataplane configuration that Kuma# generates automatically and add more customizations on top of itimports:# `default-proxy` is a reference name for the default# data plane proxy configuration generated by Kuma- default-proxy
In these examples, note:
- The
selectorsobject specifies the data plane proxies that are targeted by theProxyTemplateresource. Values are provided as Kuma tags. - The
importsobject specifies the reusable configuration that Kuma generates automatically. Kuma then extends the imports object with the custom configuration you specify. The value must be one or both ofdefault-proxy– the default configuration for non-ingress data planes – oringress– the default configuration for zone-ingress proxy.
Modifications
To customize the configuration of data plane proxies, you can combine modifications of any type in one ProxyTemplate. Each modification consists of the following sections:
operation- operation applied to the generated config (e.g.add,remove,patch).match- some operations can be applied on matched resources (e.g. remove only resource of given name, patch all outbound resources).value- raw Envoy xDS configuration. Can be partial if operation ispatch.
Origin
All resources generated by Kuma are marked with the origin value, so you can match resources. Examples: add new filters but only on inbound listeners, set timeouts on outbound clusters.
Available origins:
inbound- resources generated for incoming traffic.outbound- resources generated for outgoing traffic.transparent- resources generated for transparent proxy functionality.prometheus- resources generated when Prometheus metrics are enabled.direct-access- resources generated for Direct Access functionality.ingress- resources generated for Zone Ingress.
Cluster
Modifications that are applied on Clusters resources.
Available operations:
add- add a new cluster or replace existing if the name is the same.remove- remove a cluster.patch- patch a part of cluster definition.
Available matchers:
name- name of the cluster.origin- origin of the cluster.- Universal
apiVersion: kuma.io/v1alpha1kind: ProxyTemplatemesh: defaultmetadata:name: custom-template-1spec:selectors:- match:kuma.io/service: backend_default_svc_80conf:imports:- default-proxymodifications:- cluster:operation: addvalue: |name: test-clusterconnectTimeout: 5stype: STATIC- cluster:operation: patchmatch: # optional: if absent, all clusters will be patchedname: test-cluster # optional: if absent, all clusters regardless of name will be patchedorigin: inbound # optional: if absent, all clusters regardless of its origin will be patchedvalue: | # you can specify only part of cluster definition that will be merged into existing clusterconnectTimeout: 5s- cluster:operation: removematch: # optional: if absent, all clusters will be removedname: test-cluster # optional: if absent, all clusters regardless of name will be removedorigin: inbound # optional: if absent, all clusters regardless of its origin will be removed
type: ProxyTemplatemesh: defaultname: custom-template-1selectors:- match:kuma.io/service: backendconf:imports:- default-proxymodifications:- cluster:operation: addvalue: |name: test-clusterconnectTimeout: 5stype: STATIC- cluster:operation: patchmatch: # optional: if absent, all clusters will be patchedname: test-cluster # optional: if absent, all clusters regardless of name will be patchedorigin: inbound # optional: if absent, all clusters regardless of its origin will be patchedvalue: | # you can specify only part of cluster definition that will be merged into existing clusterconnectTimeout: 5s- cluster:operation: removematch: # optional: if absent, all clusters will be removedname: test-cluster # optional: if absent, all clusters regardless of name will be removedorigin: inbound # optional: if absent, all clusters regardless of its origin will be removed
Listener
Modifications that are applied on Listeners resources.
Available operations:
add- add a new listener or replace existing if the name is the same.remove- remove a listener.patch- patch a part of listener definition.
Available matchers:
name- name of the listener.origin- origin of the listener.- Universal
apiVersion: kuma.io/v1alpha1kind: ProxyTemplatemesh: defaultmetadata:name: custom-template-1spec:selectors:- match:kuma.io/service: backend_default_svc_80conf:imports:- default-proxymodifications:- listener:operation: addvalue: |name: test-listeneraddress:socketAddress:address: 192.168.0.1portValue: 8080- listener:operation: patchmatch: # optional: if absent, all listeners will be patchedname: test-listener # optional: if absent, all listeners regardless of name will be patchedorigin: inbound # optional: if absent, all listeners regardless of its origin will be patchedvalue: | # you can specify only part of listener definition that will be merged into existing listenercontinueOnListenerFiltersTimeout: true- listener:operation: removematch: # optional: if absent, all listeners will be removedname: test-listener # optional: if absent, all listeners regardless of name will be removedorigin: inbound # optional: if absent, all listeners regardless of its origin will be removed
type: ProxyTemplatemesh: defaultname: custom-template-1selectors:- match:kuma.io/service: backendconf:imports:- default-proxymodifications:- listener:operation: addvalue: |name: test-listeneraddress:socketAddress:address: 192.168.0.1portValue: 8080- listener:operation: patchmatch: # optional: if absent, all listeners will be patchedname: test-listener # optional: if absent, all listeners regardless of name will be patchedorigin: inbound # optional: if absent, all listeners regardless of its origin will be patchedvalue: | # you can specify only part of listener definition that will be merged into existing listenercontinueOnListenerFiltersTimeout: true- listener:operation: removematch: # optional: if absent, all listeners will be removedname: test-listener # optional: if absent, all listeners regardless of name will be removedorigin: inbound # optional: if absent, all listeners regardless of its origin will be removed
Network Filter
Modifications that are applied on Network Filters that are part of Listeners resource. Modifications are applied on all Filter Chains in the Listener.
Available operations:
addFirst- add a new filter as a first filter in Filter Chain.addLast- add a new filter as a last filter in Filter Chain.addAfter- add a new filter after other filter in Filter Chain that is matched usingmatchsection.addBefore- add a new filter before other filter in Filter Chain that is matched usingmatchsection.patch- patch a matched filter in Filter Chain.remove- remove a filter in Filter Chain.
Available matchers:
name- name of the network filter.listenerName- name of the listener.origin- origin of the listener.- Universal
apiVersion: kuma.io/v1alpha1kind: ProxyTemplatemesh: defaultmetadata:name: custom-template-1spec:selectors:- match:kuma.io/service: backend_default_svc_80conf:imports:- default-proxymodifications:- networkFilter:operation: addFirstmatch: # optional: if absent, filter will be added to all listenerslistenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.network.local_ratelimittypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimitstatPrefix: rateLimittokenBucket:fillInterval: 1s- networkFilter:operation: addLastmatch: # optional: if absent, filter will be added to all listenerslistenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.network.local_ratelimittypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimitstatPrefix: rateLimittokenBucket:fillInterval: 1s- networkFilter:operation: addBeforematch:name: envoy.filters.network.tcp_proxy # a new filter (Local RateLimit) will be added before existing (TcpProxy). If there is no TcpProxy filter, Local RateLimit won't be added.listenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.network.local_ratelimittypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimitstatPrefix: rateLimittokenBucket:fillInterval: 1s- networkFilter:operation: addAftermatch:name: envoy.filters.network.tcp_proxy # a new filter (Local RateLimit) will be added after existing (TcpProxy). If there is no TcpProxy filter, Local RateLimit won't be added.listenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.network.local_ratelimittypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimitstatPrefix: rateLimittokenBucket:fillInterval: 1s- networkFilter:operation: patchmatch:name: envoy.filters.network.tcp_proxylistenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be patched within all listeners regardless of nameorigin: inbound # optional: if absent, filter will be patched within all listeners regardless of its originvalue: | # you can specify only part of filter definition that will be merged into existing filtername: envoy.filters.network.tcp_proxytypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxyidleTimeout: 10s- networkFilter:operation: removematch: # optional: if absent, all filters from all listeners will be removedname: envoy.filters.network.tcp_proxy # optional: if absent, all filters regardless of name will be removedlistenerName: inbound:127.0.0.0:80 # optional: if absent, all filters regardless of the listener name will be removedorigin: inbound # optional: if absent, all filters regardless of its origin will be removed
type: ProxyTemplatemesh: defaultname: custom-template-1selectors:- match:kuma.io/service: backendconf:imports:- default-proxymodifications:- networkFilter:operation: addFirstmatch: # optional: if absent, filter will be added to all listenerslistenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.network.local_ratelimittypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimitstatPrefix: rateLimittokenBucket:fillInterval: 1s- networkFilter:operation: addLastmatch: # optional: if absent, filter will be added to all listenerslistenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.network.local_ratelimittypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimitstatPrefix: rateLimittokenBucket:fillInterval: 1s- networkFilter:operation: addBeforematch:name: envoy.filters.network.tcp_proxy # a new filter (Local RateLimit) will be added before existing (TcpProxy). If there is no TcpProxy filter, Local RateLimit won't be added.listenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.network.local_ratelimittypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimitstatPrefix: rateLimittokenBucket:fillInterval: 1s- networkFilter:operation: addAftermatch:name: envoy.filters.network.tcp_proxy # a new filter (Local RateLimit) will be added after existing (TcpProxy). If there is no TcpProxy filter, Local RateLimit won't be added.listenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.network.local_ratelimittypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimitstatPrefix: rateLimittokenBucket:fillInterval: 1s- networkFilter:operation: patchmatch:name: envoy.filters.network.tcp_proxylistenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be patched within all listeners regardless of nameorigin: inbound # optional: if absent, filter will be patched within all listeners regardless of its originvalue: | # you can specify only part of filter definition that will be merged into existing filtername: envoy.filters.network.tcp_proxytypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxyidleTimeout: 10s- networkFilter:operation: removematch: # optional: if absent, all filters from all listeners will be removedname: envoy.filters.network.tcp_proxy # optional: if absent, all filters regardless of name will be removedlistenerName: inbound:127.0.0.0:80 # optional: if absent, all filters regardless of the listener name will be removedorigin: inbound # optional: if absent, all filters regardless of its origin will be removed
HTTP Filter
Modifications that are applied on HTTP Filters that are part of Listeners resource. Modifications are applied on all HTTP Connection Managers in the Listener.
Available operations:
addFirst- add a new filter as a first filter in HTTP Connection Manager.addLast- add a new filter as a last filter in HTTP Connection Manager.addAfter- add a new filter after other filter in HTTP Connection Manager that is matched usingmatchsection.addBefore- add a new filter before other filter in HTTP Connection Manager that is matched usingmatchsection.patch- patch a matched filter in HTTP Connection Manager.remove- remove a filter in HTTP Connection Manager.
Available matchers:
name- name of the network filterlistenerName- name of the listenerorigin- origin of the listener- Universal
apiVersion: kuma.io/v1alpha1kind: ProxyTemplatemesh: defaultmetadata:name: custom-template-1spec:selectors:- match:kuma.io/service: backend_default_svc_80conf:imports:- default-proxymodifications:- httpFilter:operation: addFirstmatch: # optional: if absent, filter will be added to all HTTP Connection ManagerslistenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.http.gziptypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.gzip.v3.GzipmemoryLevel: 9- httpFilter:operation: addLastmatch: # optional: if absent, filter will be added to all HTTP Connection ManagerslistenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.http.gziptypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.gzip.v3.GzipmemoryLevel: 9- httpFilter:operation: addBeforematch:name: envoy.filters.http.router # a new filter (Gzip) will be added before existing (Router). If there is no Router filter, Gzip won't be added.listenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.http.gziptypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.gzip.v3.GzipmemoryLevel: 9- httpFilter:operation: addAftermatch:name: envoy.filters.http.router # a new filter (Gzip) will be added after existing (Router). If there is no Router filter, Gzip won't be added.listenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.http.gziptypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.gzip.v3.GzipmemoryLevel: 9- httpFilter:operation: patchmatch:name: envoy.filters.http.routerlistenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be patched within all listeners regardless of nameorigin: inbound # optional: if absent, filter will be patched within all listeners regardless of its originvalue: | # you can specify only part of filter definition that will be merged into existing filtername: envoy.filters.http.routertypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.RouterdynamicStats: false- httpFilter:operation: removematch: # optional: if absent, all filters from all listeners will be removedname: envoy.filters.http.gzip # optional: if absent, all filters regardless of name will be removedlistenerName: inbound:127.0.0.0:80 # optional: if absent, all filters regardless of the listener name will be removedorigin: inbound # optional: if absent, all filters regardless of its origin will be removed
type: ProxyTemplatemesh: defaultname: custom-template-1selectors:- match:kuma.io/service: backendconf:imports:- default-proxymodifications:- httpFilter:operation: addFirstmatch: # optional: if absent, filter will be added to all HTTP Connection ManagerslistenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.http.gziptypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.gzip.v3.GzipmemoryLevel: 9- httpFilter:operation: addLastmatch: # optional: if absent, filter will be added to all HTTP Connection ManagerslistenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.http.gziptypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.gzip.v3.GzipmemoryLevel: 9- httpFilter:operation: addBeforematch:name: envoy.filters.http.router # a new filter (Gzip) will be added before existing (Router). If there is no Router filter, Gzip won't be added.listenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.http.gziptypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.gzip.v3.GzipmemoryLevel: 9- httpFilter:operation: addAftermatch:name: envoy.filters.http.router # a new filter (Gzip) will be added after existing (Router). If there is no Router filter, Gzip won't be added.listenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be added to all listeners regardless of nameorigin: inbound # optional: if absent, filter will be added to all listeners regardless of its originvalue: |name: envoy.filters.http.gziptypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.gzip.v3.GzipmemoryLevel: 9- httpFilter:operation: patchmatch:name: envoy.filters.http.routerlistenerName: inbound:127.0.0.0:80 # optional: if absent, filter will be patched within all listeners regardless of nameorigin: inbound # optional: if absent, filter will be patched within all listeners regardless of its originvalue: | # you can specify only part of filter definition that will be merged into existing filtername: envoy.filters.http.routertypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.RouterdynamicStats: false- httpFilter:operation: removematch: # optional: if absent, all filters from all listeners will be removedname: envoy.filters.http.gzip # optional: if absent, all filters regardless of name will be removedlistenerName: inbound:127.0.0.0:80 # optional: if absent, all filters regardless of the listener name will be removedorigin: inbound # optional: if absent, all filters regardless of its origin will be removed
VirtualHost
Modifications that are applied on VirtualHost resources.
Available operations:
add- add a new VirtualHost.remove- remove a VirtualHost.patch- patch a part of VirtualHost definition.
Available matchers:
name- name of the VirtualHost.origin- origin of the VirtualHost.routeConfigurationName- name of the RouteConfiguration.- Universal
apiVersion: kuma.io/v1alpha1kind: ProxyTemplatemesh: defaultmetadata:name: custom-template-1spec:selectors:- match:kuma.io/service: backend_default_svc_80conf:imports:- default-proxymodifications:- virtualHost:operation: addvalue: |name: backenddomains:- "*"routes:- match:prefix: /route:cluster: backend- virtualHost:operation: patchmatch: # optional: if absent, all listeners will be patchedname: backend # optional: if absent, all virtual hosts regardless of name will be patchedorigin: inbound # optional: if absent, all virtual hosts regardless of its origin will be patchedrouteConfigurationName: outbound:backend # optional: if absent, all virtual hosts in all route configurations will be patchedvalue: | # you can specify only part of virtual host definition that will be merged into existing virtual hostretryPolicy:retryOn: 5xxnumRetries: 3- virtualHost:operation: removematch: # optional: if absent, all virtual hosts will be removedname: test-listener # optional: if absent, all virtual hsots regardless of name will be removedorigin: inbound # optional: if absent, all virtual hosts regardless of its origin will be removed
type: ProxyTemplatemesh: defaultname: custom-template-1selectors:- match:kuma.io/service: backendconf:imports:- default-proxymodifications:- virtualHost:operation: addvalue: |name: backenddomains:- "*"routes:- match:prefix: /route:cluster: backend- virtualHost:operation: patchmatch: # optional: if absent, all listeners will be patchedname: backend # optional: if absent, all virtual hosts regardless of name will be patchedorigin: inbound # optional: if absent, all virtual hosts regardless of its origin will be patchedrouteConfigurationName: outbound:backend # optional: if absent, all virtual hosts in all route configurations will be patchedvalue: | # you can specify only part of virtual host definition that will be merged into existing virtual hostretryPolicy:retryOn: 5xxnumRetries: 3- virtualHost:operation: removematch: # optional: if absent, all virtual hosts will be removedname: test-listener # optional: if absent, all virtual hsots regardless of name will be removedorigin: inbound # optional: if absent, all virtual hosts regardless of its origin will be removed
How Kuma handles the proxy template
At runtime, whenever kuma-cp generates the configuration for a given data plane proxy, it will proceed as follows:
- Kuma searches for all the
ProxyTemplatesresources that have been defined in the specified Mesh. - It loads in memory the
ProxyTemplatesresources whoseselectorsmatch either aninboundor agatewaydefinition of any data plane proxy accordingly to the Kuma Tags selected. - Every matching
ProxyTemplateis ranked. TheProxyTemplateresource with the highest ranking is used to generate the configuration for the specified data plane proxy (or proxies). - If the
ProxyTemplateresource specifies animportsobject, these resources are generated first. - If a
ProxyTemplatedefines amodificationobject, all modifications are applied, one by one in the order defined inmodificationsection.
Lua filter example
For a more complete example, explore this Lua filter that adds the new x-header: test header to all outgoing HTTP requests.
apiVersion: kuma.io/v1alpha1kind: ProxyTemplatemesh: defaultmetadata:name: backend-lua-filterspec:selectors:- match:kuma.io/service: backend_default_svc_80conf:imports:- default-proxy # apply modifications on top of resources generated by Kumamodifications:- httpFilter:operation: addBeforematch:name: envoy.filters.http.routerorigin: outboundvalue: |name: envoy.filters.http.luatypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Luainline_code: |function envoy_on_request(request_handle)request_handle:headers():add("x-header", "test")end
type: ProxyTemplatemesh: defaultname: backend-lua-filterselectors:- match:kuma.io/service: backendconf:imports:- default-proxy # apply modifications on top of resources generated by Kumamodifications:- httpFilter:operation: addBeforematch:name: envoy.filters.http.routerorigin: outboundvalue: |name: envoy.filters.http.luatypedConfig:'@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Luainline_code: |function envoy_on_request(request_handle)request_handle:headers():add("x-header", "test")end
Matching
ProxyTemplate is a Dataplane policy. You can use all the tags in the selectors section.
