Skip to content

Commit

Permalink
listeners: add unified matcher for filter chains (envoyproxy#20110)
Browse files Browse the repository at this point in the history
Add unified matcher for network streams, as a replacement for filter chain match. 

See previous discussion in envoyproxy#18871

Signed-off-by: Kuat Yessenov <kuat@google.com>
  • Loading branch information
kyessenov authored and ravenblackx committed Jun 8, 2022
1 parent 50df9b5 commit c8acc6d
Show file tree
Hide file tree
Showing 19 changed files with 1,786 additions and 533 deletions.
2 changes: 2 additions & 0 deletions api/envoy/config/listener/v3/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ api_proto_package(
"//envoy/config/core/v3:pkg",
"//envoy/type/v3:pkg",
"@com_github_cncf_udpa//udpa/annotations:pkg",
"@com_github_cncf_udpa//xds/annotations/v3:pkg",
"@com_github_cncf_udpa//xds/core/v3:pkg",
"@com_github_cncf_udpa//xds/type/matcher/v3:pkg",
],
)
23 changes: 22 additions & 1 deletion api/envoy/config/listener/v3/listener.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import "envoy/config/listener/v3/udp_listener_config.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/wrappers.proto";

import "xds/annotations/v3/status.proto";
import "xds/core/v3/collection_entry.proto";
import "xds/type/matcher/v3/matcher.proto";

import "envoy/annotations/deprecation.proto";
import "udpa/annotations/security.proto";
Expand All @@ -36,7 +38,7 @@ message ListenerCollection {
repeated xds.core.v3.CollectionEntry entries = 1;
}

// [#next-free-field: 32]
// [#next-free-field: 33]
message Listener {
option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Listener";

Expand Down Expand Up @@ -120,6 +122,25 @@ message Listener {
// :ref:`FAQ entry <faq_how_to_setup_sni>`.
repeated FilterChain filter_chains = 3;

// :ref:`Matcher API <arch_overview_matching_listener>` resolving the filter chain name from the
// network properties. This matcher is used as a replacement for the filter chain match condition
// :ref:`filter_chain_match
// <envoy_v3_api_field_config.listener.v3.FilterChain.filter_chain_match>`. If specified, all
// :ref:`filter_chains <envoy_v3_api_field_config.listener.v3.Listener.filter_chains>` must have a
// non-empty and unique :ref:`name <envoy_v3_api_field_config.listener.v3.FilterChain.name>` field
// and not specify :ref:`filter_chain_match
// <envoy_v3_api_field_config.listener.v3.FilterChain.filter_chain_match>` field.
//
// .. note::
//
// Once matched, each connection is permanently bound to its filter chain.
// If the matcher changes but the filter chain remains the same, the
// connections bound to the filter chain are not drained. If, however, the
// filter chain is removed or structurally modified, then the drain for its
// connections is initiated.
xds.type.matcher.v3.Matcher filter_chain_matcher = 32
[(xds.annotations.v3.field_status).work_in_progress = true];

// If a connection is redirected using *iptables*, the port on which the proxy
// receives it might be different from the original destination address. When this flag is set to
// true, the listener hands off redirected connections to the listener associated with the
Expand Down
11 changes: 7 additions & 4 deletions api/envoy/config/listener/v3/listener_components.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/wrappers.proto";

import "xds/annotations/v3/status.proto";

import "envoy/annotations/deprecation.proto";
import "udpa/annotations/status.proto";
import "udpa/annotations/versioning.proto";
Expand Down Expand Up @@ -258,10 +260,11 @@ message FilterChain {
// establishment, the connection is summarily closed.
google.protobuf.Duration transport_socket_connect_timeout = 9;

// [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no
// name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter
// chain is to be dynamically updated or removed via FCDS a unique name must be provided.
string name = 7;
// The unique name (or empty) by which this filter chain is known.
// Note: :ref:`filter_chain_matcher
// <envoy_v3_api_field_config.listener.v3.Listener.filter_chain_matcher>`
// requires that filter chains are uniquely named within a listener.
string name = 7 [(xds.annotations.v3.field_status).work_in_progress = true];

// [#not-implemented-hide:] The configuration to specify whether the filter chain will be built on-demand.
// If this field is not empty, the filter chain will be built on-demand.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
static_resources:
listeners:
- name: outbound
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 15000
listener_filters:
- name: original_dst
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.original_dst.v3.OriginalDst
traffic_direction: OUTBOUND
filter_chains:
- name: http
filters:
- name: http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: some_service
http_filters:
- name: router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- name: internal
filters:
- name: tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
stat_prefix: internal
cluster: some_service
- name: tls
transport_socket:
name: tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificates:
- certificate_chain: {filename: "certs/servercert.pem"}
private_key: {filename: "certs/serverkey.pem"}
filters:
- name: tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
stat_prefix: tls
cluster: some_service
# Snippet: 58-102
filter_chain_matcher:
matcher_tree:
input:
name: port
typed_config:
"@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationPortInput
exact_match_map:
map:
"80":
action:
name: http
typed_config:
"@type": type.googleapis.com/google.protobuf.StringValue
value: http
"443":
matcher:
matcher_tree:
input:
name: ip
typed_config:
"@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.SourceIPInput
custom_match:
name: ip-matcher
typed_config:
"@type": type.googleapis.com/xds.type.matcher.v3.IPMatcher
range_matchers:
- ranges:
- address_prefix: 192.0.0.0
prefix_len: 2
- address_prefix: 10.0.0.0
prefix_len: 24
on_match:
action:
name: internal
typed_config:
"@type": type.googleapis.com/google.protobuf.StringValue
value: internal
- ranges:
- address_prefix: 0.0.0.0
on_match:
action:
name: tls
typed_config:
"@type": type.googleapis.com/google.protobuf.StringValue
value: tls

clusters:
- name: some_service
load_assignment:
cluster_name: some_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 10.1.2.10
port_value: 10002
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
static_resources:
listeners:
- name: outbound
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 8443
listener_filters:
- name: tls_inspector
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
filter_chains:
- name: tls
transport_socket:
name: tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificates:
- certificate_chain: {filename: "certs/servercert.pem"}
private_key: {filename: "certs/serverkey.pem"}
filters:
- name: tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
stat_prefix: tls
cluster: some_service
- name: plaintext
filters:
- name: tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
stat_prefix: plaintext
cluster: some_service
# Snippet: 37-56
filter_chain_matcher:
matcher_tree:
input:
name: transport
typed_config:
"@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.TransportProtocolInput
exact_match_map:
map:
"tls":
action:
name: tls
typed_config:
"@type": type.googleapis.com/google.protobuf.StringValue
value: tls
on_no_match:
action:
name: plaintext
typed_config:
"@type": type.googleapis.com/google.protobuf.StringValue
value: plaintext

clusters:
- name: some_service
load_assignment:
cluster_name: some_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 10.1.2.10
port_value: 10002
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
static_resources:
listeners:
- name: outbound
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 15000
listener_filters:
- name: proxy_protocol
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.proxy_protocol.v3.ProxyProtocol
filter_chains:
- name: vip
filters:
- name: tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
stat_prefix: vip
cluster: original_dst
- name: default
filters:
- name: tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
stat_prefix: default
cluster: original_dst
# Snippet: 29-48
filter_chain_matcher:
matcher_tree:
input:
name: destination_ip
typed_config:
"@type": type.googleapis.com/envoy.extensions.matching.common_inputs.network.v3.DestinationIPInput
prefix_match_map:
map:
"10.0.0.":
action:
name: vip
typed_config:
"@type": type.googleapis.com/google.protobuf.StringValue
value: vip
on_no_match:
action:
name: default
typed_config:
"@type": type.googleapis.com/google.protobuf.StringValue
value: default

clusters:
- name: original_dst
type: ORIGINAL_DST
lb_policy: CLUSTER_PROVIDED
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ Generic Matching
:maxdepth: 2

matching_api
matching_listener
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
.. _arch_overview_matching_listener:

Matching Filter Chains in Listeners
===================================

Envoy listeners implement the :ref:`matching API <envoy_v3_api_msg_.xds.type.matcher.v3.Matcher>` for selecting a filter
chain based on a collection of :ref:`network inputs <extension_category_envoy.matching.network.input>`. Matching is done
once per connection. Connections are drained when the associated named filter chain configuration changes, but not when
the filter chain matcher is the only updated field in a listener.

The action in the matcher API must be a string value corresponding to the name of the filter chain. If there is no
filter chain with the given name, the match fails, and the :ref:`default filter chain
<envoy_v3_api_field_config.listener.v3.Listener.default_filter_chain>` is used if specified, or the connection is
rejected. Filter chain matcher requires that all filter chains in a listener are uniquely named.

The matcher API replaces the existing filter :ref:`filter_chain_match
<envoy_v3_api_field_config.listener.v3.FilterChain.filter_chain_match>` field. When using the matcher API, the filter
chain match field is ignored and should not be set.

Examples
########

Detect TLS traffic
******************

The following examples uses :ref:`tls_inspector <config_listener_filters_tls_inspector>` listener filter to detect
whether the transport appears to be TLS, in which case the matcher in the listener selects the filter chain ``tls``.
Otherwise, the filter chain ``plaintext`` is used.

.. literalinclude:: _include/listener_tls.yaml
:language: yaml
:lines: 37-56
:caption: :download:`listener_tls.yaml <_include/listener_tls.yaml>`

Match Against the Destination IP
********************************

The following example assumes :ref:`PROXY protocol <config_listener_filters_proxy_protocol>` is used for incoming
traffic. If the recovered destination IP is in CIDR ``10.0.0.0/24``, then the filter chain ``vip`` is used. Otherwise,
the filter chain ``default`` is used.

.. literalinclude:: _include/listener_vip.yaml
:language: yaml
:lines: 29-48
:caption: :download:`listener_vip.yaml <_include/listener_vip.yaml>`

Match Against the Destination Port and the Source IP
****************************************************

The following example uses :ref:`original_dst <config_listener_filters_original_dst>` listener filter to recover the
original destination port. The matcher in the listener selects one of the three filter chains ``http``, ``internal``,
and ``tls`` as follows:

* If the destination port is ``80``, then the filter chain ``http`` accepts the connection.
* If the destination port is ``443`` and the source IP is in the range ``192.0.0.0/2`` or ``10.0.0.0/24``, then the
filter chain ``internal`` accepts the connection. If the source IP is not in the ranges then the filter chain ``tls``
accepts the connection.
* Otherwise, the connection is rejected, because there is no default filter chain.

.. literalinclude:: _include/listener_complicated.yaml
:language: yaml
:lines: 58-102
:caption: :download:`listener_complicated.yaml <_include/listener_complicated.yaml>`
Loading

0 comments on commit c8acc6d

Please sign in to comment.