blob: 125f5c3b46bde492690ab1d33bd6a2ddcf070720 [file] [log] [blame]
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package envoyfilter
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
import (
udpa "github.com/cncf/xds/go/udpa/type/v1"
core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
listener "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
fault "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/fault/v3"
http_conn "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
redis "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/redis_proxy/v3"
tcp_proxy "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/tcp_proxy/v3"
tls "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
"github.com/envoyproxy/go-control-plane/pkg/wellknown"
"github.com/golang/protobuf/jsonpb" // nolint: staticcheck
"github.com/golang/protobuf/ptypes/wrappers"
"github.com/google/go-cmp/cmp"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/wrapperspb"
meshconfig "istio.io/api/mesh/v1alpha1"
networking "istio.io/api/networking/v1alpha3"
)
import (
"github.com/apache/dubbo-go-pixiu/pilot/pkg/config/kube/crd"
"github.com/apache/dubbo-go-pixiu/pilot/pkg/config/memory"
"github.com/apache/dubbo-go-pixiu/pilot/pkg/model"
"github.com/apache/dubbo-go-pixiu/pilot/pkg/networking/util"
memregistry "github.com/apache/dubbo-go-pixiu/pilot/pkg/serviceregistry/memory"
"github.com/apache/dubbo-go-pixiu/pkg/config"
"github.com/apache/dubbo-go-pixiu/pkg/config/mesh"
"github.com/apache/dubbo-go-pixiu/pkg/config/schema/collections"
"github.com/apache/dubbo-go-pixiu/pkg/config/schema/gvk"
istio_proto "github.com/apache/dubbo-go-pixiu/pkg/proto"
"github.com/apache/dubbo-go-pixiu/pkg/test/env"
"github.com/apache/dubbo-go-pixiu/pkg/util/protomarshal"
)
var testMesh = &meshconfig.MeshConfig{
ConnectTimeout: &durationpb.Duration{
Seconds: 10,
Nanos: 1,
},
}
func buildEnvoyFilterConfigStore(configPatches []*networking.EnvoyFilter_EnvoyConfigObjectPatch) model.ConfigStore {
store := model.MakeIstioStore(memory.Make(collections.Pilot))
for i, cp := range configPatches {
store.Create(config.Config{
Meta: config.Meta{
Name: fmt.Sprintf("test-envoyfilter-%d", i),
Namespace: "not-default",
GroupVersionKind: gvk.EnvoyFilter,
},
Spec: &networking.EnvoyFilter{
ConfigPatches: []*networking.EnvoyFilter_EnvoyConfigObjectPatch{cp},
},
})
}
return store
}
func buildPatchStruct(config string) *structpb.Struct {
val := &structpb.Struct{}
_ = jsonpb.Unmarshal(strings.NewReader(config), val)
return val
}
// nolint: unparam
func buildGolangPatchStruct(config string) *structpb.Struct {
val := &structpb.Struct{}
_ = protomarshal.Unmarshal([]byte(config), val)
return val
}
func newTestEnvironment(serviceDiscovery model.ServiceDiscovery, meshConfig *meshconfig.MeshConfig,
configStore model.ConfigStore) *model.Environment {
e := &model.Environment{
ServiceDiscovery: serviceDiscovery,
ConfigStore: configStore,
Watcher: mesh.NewFixedWatcher(meshConfig),
}
e.PushContext = model.NewPushContext()
e.Init()
_ = e.PushContext.InitContext(e, nil, nil)
return e
}
func TestApplyListenerPatches(t *testing.T) {
configPatches := []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
{
ApplyTo: networking.EnvoyFilter_LISTENER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_OUTBOUND,
Proxy: &networking.EnvoyFilter_ProxyMatch{
Metadata: map[string]string{"foo": "sidecar"},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_ADD,
Value: buildPatchStruct(`{"name":"new-outbound-listener1"}`),
},
},
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_OUTBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 12345,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{Name: "filter1"},
},
},
},
Proxy: &networking.EnvoyFilter_ProxyMatch{
ProxyVersion: `^1\.[2-9](.*?)$`,
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_BEFORE,
Value: buildPatchStruct(`{"name":"filter0"}`),
},
},
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_OUTBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 12345,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{Name: "filter1"},
},
},
},
Proxy: &networking.EnvoyFilter_ProxyMatch{
ProxyVersion: `^1\.[5-9](.*?)$`,
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_FIRST,
Value: buildPatchStruct(`{"name":"filter0"}`),
},
},
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_OUTBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 12345,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{Name: "filter2"},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REMOVE,
},
},
{
ApplyTo: networking.EnvoyFilter_LISTENER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 12345,
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REMOVE,
},
},
{
ApplyTo: networking.EnvoyFilter_LISTENER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`{listener_filters: nil}`),
},
},
{
ApplyTo: networking.EnvoyFilter_FILTER_CHAIN,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{TransportProtocol: "tls"},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REMOVE,
},
},
{
ApplyTo: networking.EnvoyFilter_LISTENER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`{"listener_filters": [{"name":"foo"}]}`),
},
},
{
ApplyTo: networking.EnvoyFilter_FILTER_CHAIN,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Sni: "*.foo.com",
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`{"filter_chain_match": { "server_names": ["foo.com"] }}`),
},
},
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{Name: wellknown.RedisProxy},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`
{"name": "envoy.filters.network.redis_proxy",
"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy",
"settings": {"op_timeout": "0.2s"}
}
}`),
},
},
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Sni: "*.foo.com",
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: wellknown.HTTPConnectionManager,
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{Name: "http-filter2"},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_AFTER,
Value: buildPatchStruct(`{"name": "http-filter3"}`),
},
},
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: wellknown.HTTPConnectionManager,
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{Name: "http-filter2"},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_BEFORE,
Value: buildPatchStruct(`{"name": "http-filter3"}`),
},
},
// Remove inline http filter patch
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: wellknown.HTTPConnectionManager,
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{Name: "http-filter3"},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_BEFORE,
Value: buildPatchStruct(`{"name": "http-filter-to-be-removed2"}`),
},
},
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: wellknown.HTTPConnectionManager,
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{Name: "http-filter-to-be-removed2"},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REMOVE,
},
},
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: wellknown.HTTPConnectionManager,
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{Name: "http-filter2"},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_AFTER,
Value: buildPatchStruct(`{"name": "http-filter4"}`),
},
},
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: wellknown.HTTPConnectionManager,
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{Name: "http-filter-to-be-removed"},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REMOVE,
},
},
// Merge v3 any with v2 any
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: wellknown.HTTPConnectionManager,
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{Name: "envoy.fault"}, // Use deprecated name for test.
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`
{"name": "envoy.filters.http.fault",
"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault",
"downstreamNodes": ["foo"]
}
}`),
},
},
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: wellknown.HTTPConnectionManager,
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{Name: "http-filter2"},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_FIRST,
Value: buildPatchStruct(`{"name": "http-filter0"}`),
},
},
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: wellknown.HTTPConnectionManager,
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
Name: wellknown.Fault,
},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`{"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault",
"upstream_cluster": "scooby"}}`),
},
},
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: wellknown.HTTPConnectionManager,
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`
{"name": "envoy.filters.network.http_connection_manager",
"typed_config": {
"@type": "type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager",
"xffNumTrustedHops": "4"
}
}`),
},
},
// Ensure we can mix v3 patches with v2 internal
// Note that alwaysSetRequestIdInResponse is only present in v3 protos. It will be silently ignored
// as we are working in v2 protos internally
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "envoy.http_connection_manager", // Use deprecated name for test.
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`
{"name": "envoy.http_connection_manager",
"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
"mergeSlashes": true,
"alwaysSetRequestIdInResponse": true
}
}`),
},
},
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "envoy.http_connection_manager", // Use deprecated name for test.
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{Name: "http-filter2"},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_AFTER,
Value: buildPatchStruct(`{"name": "http-filter-5"}`),
},
},
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 6379,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "filter1",
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REPLACE,
Value: buildPatchStruct(`
{"name": "envoy.redis_proxy",
"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy",
"stat_prefix": "redis_stats",
"prefix_routes": {
"catch_all_route": {
"cluster": "custom-redis-cluster"
}
}
}
}`),
},
},
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 6381,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "default-network-filter",
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REPLACE,
Value: buildPatchStruct(`{"name": "default-network-filter-replaced"}`),
},
},
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 6381,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "default-network-filter-removed",
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REMOVE,
},
},
// This patch should not be applied because network filter name doesn't match
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 6380,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "network-filter-should-not-be-replaced-not-match",
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REPLACE,
Value: buildPatchStruct(`{"name": "network-filter-replaced-should-not-be-applied"}`),
},
},
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
Name: "listener-http-filter-to-be-replaced",
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: wellknown.HTTPConnectionManager,
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
Name: "http-filter-to-be-replaced",
},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REPLACE,
Value: buildPatchStruct(`{"name": "http-filter-replaced"}`),
},
},
// This patch should not be applied because the subfilter name doesn't match
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
Name: "listener-http-filter-to-be-replaced-not-found",
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: wellknown.HTTPConnectionManager,
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
Name: "http-filter-should-not-be-replaced-not-match",
},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REPLACE,
Value: buildPatchStruct(`{"name": "http-filter-replaced-should-not-be-applied"}`),
},
},
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
Name: model.VirtualInboundListenerName,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
DestinationPort: 6380,
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "network-filter-to-be-replaced",
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REPLACE,
Value: buildPatchStruct(`
{"name": "envoy.redis_proxy",
"typed_config": {
"@type": "type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy",
"stat_prefix": "redis_stats",
"prefix_routes": {
"catch_all_route": {
"cluster": "custom-redis-cluster"
}
}
}
}`),
},
},
{
ApplyTo: networking.EnvoyFilter_FILTER_CHAIN,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_OUTBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 12345,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{TransportProtocol: "tls"},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`
{"transport_socket":{
"name":"envoy.transport_sockets.tls",
"typed_config":{
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"common_tls_context":{
"tls_params":{
"tls_maximum_protocol_version":"TLSv1_3",
"tls_minimum_protocol_version":"TLSv1_2"}}}}}`),
},
},
// Patch custom TLS type
{
ApplyTo: networking.EnvoyFilter_FILTER_CHAIN,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_OUTBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 7777,
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`
{"transport_socket":{
"name":"transport_sockets.alts",
"typed_config":{
"@type":"type.googleapis.com/udpa.type.v1.TypedStruct",
"type_url": "type.googleapis.com/envoy.extensions.transport_sockets.alts.v3.Alts",
"value":{"handshaker_service":"1.2.3.4"}}}}`),
},
},
// Patch custom TLS type to a FC without TLS already set
{
ApplyTo: networking.EnvoyFilter_FILTER_CHAIN,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_OUTBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 7778,
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`
{"transport_socket":{
"name":"transport_sockets.alts",
"typed_config":{
"@type":"type.googleapis.com/udpa.type.v1.TypedStruct",
"type_url": "type.googleapis.com/envoy.extensions.transport_sockets.alts.v3.Alts",
"value":{"handshaker_service":"1.2.3.4"}}}}`),
},
},
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
Name: model.VirtualInboundListenerName,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Name: "filter-chain-name-match",
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "custom-network-filter-2",
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REMOVE,
},
},
// Remove inline network filter patch
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
Name: model.VirtualInboundListenerName,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Name: "filter-chain-name-match",
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "custom-network-filter-1",
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_INSERT_BEFORE,
Value: buildPatchStruct(`{"name":"network-filter-to-be-removed"}`),
},
},
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
Name: model.VirtualInboundListenerName,
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Name: "filter-chain-name-match",
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "network-filter-to-be-removed",
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_REMOVE,
},
},
// Add transport socket to virtual inbound.
{
ApplyTo: networking.EnvoyFilter_FILTER_CHAIN,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 80,
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`
{"transport_socket":{
"name":"envoy.transport_sockets.tls",
"typed_config":{
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"common_tls_context":{
"alpn_protocols": [ "h2-80", "http/1.1-80" ]}}}}`),
},
},
{
ApplyTo: networking.EnvoyFilter_FILTER_CHAIN,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_SIDECAR_INBOUND,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
PortNumber: 6380,
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: buildPatchStruct(`
{"transport_socket":{
"name":"envoy.transport_sockets.tls",
"typed_config":{
"@type":"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext",
"common_tls_context":{
"alpn_protocols": [ "h2-6380", "http/1.1-6380" ]}}}}`),
},
},
}
sidecarOutboundIn := []*listener.Listener{
{
Name: "12345",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 12345,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{TransportProtocol: "tls"},
TransportSocket: &core.TransportSocket{
Name: "envoy.transport_sockets.tls",
ConfigType: &core.TransportSocket_TypedConfig{
TypedConfig: util.MessageToAny(&tls.DownstreamTlsContext{
CommonTlsContext: &tls.CommonTlsContext{
TlsParams: &tls.TlsParameters{
EcdhCurves: []string{"X25519"},
TlsMaximumProtocolVersion: tls.TlsParameters_TLSv1_1,
},
},
}),
},
},
Filters: []*listener.Filter{{Name: "envoy.transport_sockets.tls"}},
},
{
Filters: []*listener.Filter{
{Name: "filter1"},
{Name: "filter2"},
},
},
},
},
{
Name: "network-filter-to-be-replaced",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 6379,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
Filters: []*listener.Filter{
{Name: "filter1"},
{Name: "filter2"},
},
},
},
},
{
Name: "redis-proxy",
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{
DestinationPort: &wrapperspb.UInt32Value{
Value: 9999,
},
},
Filters: []*listener.Filter{
{
Name: wellknown.RedisProxy,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&redis.RedisProxy{
Settings: &redis.RedisProxy_ConnPoolSettings{
OpTimeout: durationpb.New(time.Second * 5),
},
}),
},
},
},
},
},
},
{
Name: "network-filter-to-be-replaced-not-found",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 6380,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
Filters: []*listener.Filter{
{Name: "network-filter-should-not-be-replaced"},
},
},
},
},
{
Name: "default-filter-chain",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 6381,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
Filters: []*listener.Filter{
{Name: "network-filter"},
},
},
},
DefaultFilterChain: &listener.FilterChain{
Filters: []*listener.Filter{
{Name: "default-network-filter"},
{Name: "default-network-filter-removed"},
},
},
},
{
Name: "another-listener",
},
{
Name: "listener-http-filter-to-be-replaced",
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{
DestinationPort: &wrapperspb.UInt32Value{
Value: 80,
},
},
Filters: []*listener.Filter{
{
Name: wellknown.HTTPConnectionManager,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&http_conn.HttpConnectionManager{
HttpFilters: []*http_conn.HttpFilter{
{Name: "http-filter-to-be-replaced"},
{Name: "another-http-filter"},
},
}),
},
},
},
},
},
},
{
Name: "listener-http-filter-to-be-replaced-not-found",
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{
DestinationPort: &wrapperspb.UInt32Value{
Value: 80,
},
},
Filters: []*listener.Filter{
{
Name: wellknown.HTTPConnectionManager,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&http_conn.HttpConnectionManager{
HttpFilters: []*http_conn.HttpFilter{
{Name: "http-filter-should-not-be-replaced"},
{Name: "another-http-filter"},
},
}),
},
},
},
},
},
},
{
Name: "custom-tls-replacement",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 7777,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
TransportSocket: &core.TransportSocket{
Name: "envoy.transport_sockets.tls",
ConfigType: &core.TransportSocket_TypedConfig{
TypedConfig: util.MessageToAny(&tls.DownstreamTlsContext{
CommonTlsContext: &tls.CommonTlsContext{
TlsParams: &tls.TlsParameters{},
},
}),
},
},
Filters: []*listener.Filter{{Name: "filter"}},
},
},
},
{
Name: "custom-tls-addition",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 7778,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
Filters: []*listener.Filter{{Name: "filter"}},
},
},
},
}
sidecarOutboundOut := []*listener.Listener{
{
Name: "12345",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 12345,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{TransportProtocol: "tls"},
TransportSocket: &core.TransportSocket{
Name: "envoy.transport_sockets.tls",
ConfigType: &core.TransportSocket_TypedConfig{
TypedConfig: util.MessageToAny(&tls.DownstreamTlsContext{
CommonTlsContext: &tls.CommonTlsContext{
TlsParams: &tls.TlsParameters{
EcdhCurves: []string{"X25519"},
TlsMaximumProtocolVersion: tls.TlsParameters_TLSv1_3,
TlsMinimumProtocolVersion: tls.TlsParameters_TLSv1_2,
},
},
}),
},
},
Filters: []*listener.Filter{{Name: "envoy.transport_sockets.tls"}},
},
{
Filters: []*listener.Filter{
{Name: "filter0"},
{Name: "filter1"},
},
},
},
},
{
Name: "network-filter-to-be-replaced",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 6379,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
Filters: []*listener.Filter{
{
Name: "envoy.redis_proxy",
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&redis.RedisProxy{
StatPrefix: "redis_stats",
PrefixRoutes: &redis.RedisProxy_PrefixRoutes{
CatchAllRoute: &redis.RedisProxy_PrefixRoutes_Route{
Cluster: "custom-redis-cluster",
},
},
}),
},
},
{Name: "filter2"},
},
},
},
},
{
Name: "redis-proxy",
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{
DestinationPort: &wrapperspb.UInt32Value{
Value: 9999,
},
},
Filters: []*listener.Filter{
{
Name: wellknown.RedisProxy,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&redis.RedisProxy{
Settings: &redis.RedisProxy_ConnPoolSettings{
OpTimeout: durationpb.New(time.Millisecond * 200),
},
}),
},
},
},
},
},
},
{
Name: "network-filter-to-be-replaced-not-found",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 6380,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
Filters: []*listener.Filter{
{Name: "network-filter-should-not-be-replaced"},
},
},
},
},
{
Name: "default-filter-chain",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 6381,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
Filters: []*listener.Filter{
{Name: "network-filter"},
},
},
},
DefaultFilterChain: &listener.FilterChain{
Filters: []*listener.Filter{
{Name: "default-network-filter-replaced"},
},
},
},
{
Name: "another-listener",
},
{
Name: "listener-http-filter-to-be-replaced",
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{
DestinationPort: &wrapperspb.UInt32Value{
Value: 80,
},
},
Filters: []*listener.Filter{
{
Name: wellknown.HTTPConnectionManager,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&http_conn.HttpConnectionManager{
HttpFilters: []*http_conn.HttpFilter{
{Name: "http-filter-replaced"},
{Name: "another-http-filter"},
},
}),
},
},
},
},
},
},
{
Name: "listener-http-filter-to-be-replaced-not-found",
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{
DestinationPort: &wrapperspb.UInt32Value{
Value: 80,
},
},
Filters: []*listener.Filter{
{
Name: wellknown.HTTPConnectionManager,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&http_conn.HttpConnectionManager{
HttpFilters: []*http_conn.HttpFilter{
{Name: "http-filter-should-not-be-replaced"},
{Name: "another-http-filter"},
},
}),
},
},
},
},
},
},
{
Name: "custom-tls-replacement",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 7777,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
TransportSocket: &core.TransportSocket{
Name: "transport_sockets.alts",
ConfigType: &core.TransportSocket_TypedConfig{
TypedConfig: util.MessageToAny(&udpa.TypedStruct{
TypeUrl: "type.googleapis.com/envoy.extensions.transport_sockets.alts.v3.Alts",
Value: buildGolangPatchStruct(`{"handshaker_service":"1.2.3.4"}`),
}),
},
},
Filters: []*listener.Filter{{Name: "filter"}},
},
},
},
{
Name: "custom-tls-addition",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 7778,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
TransportSocket: &core.TransportSocket{
Name: "transport_sockets.alts",
ConfigType: &core.TransportSocket_TypedConfig{
TypedConfig: util.MessageToAny(&udpa.TypedStruct{
TypeUrl: "type.googleapis.com/envoy.extensions.transport_sockets.alts.v3.Alts",
Value: buildGolangPatchStruct(`{"handshaker_service":"1.2.3.4"}`),
}),
},
},
Filters: []*listener.Filter{{Name: "filter"}},
},
},
},
{
Name: "new-outbound-listener1",
},
}
sidecarOutboundInNoAdd := []*listener.Listener{
{
Name: "12345",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 12345,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{TransportProtocol: "tls"},
TransportSocket: &core.TransportSocket{
Name: "envoy.transport_sockets.tls",
ConfigType: &core.TransportSocket_TypedConfig{
TypedConfig: util.MessageToAny(&tls.DownstreamTlsContext{}),
},
},
Filters: []*listener.Filter{{Name: "envoy.transport_sockets.tls"}},
},
{
Filters: []*listener.Filter{
{Name: "filter1"},
{Name: "filter2"},
},
},
},
},
{
Name: "another-listener",
},
}
sidecarOutboundOutNoAdd := []*listener.Listener{
{
Name: "12345",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 12345,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{TransportProtocol: "tls"},
TransportSocket: &core.TransportSocket{
Name: "envoy.transport_sockets.tls",
ConfigType: &core.TransportSocket_TypedConfig{
TypedConfig: util.MessageToAny(&tls.DownstreamTlsContext{
CommonTlsContext: &tls.CommonTlsContext{
TlsParams: &tls.TlsParameters{
TlsMaximumProtocolVersion: tls.TlsParameters_TLSv1_3,
TlsMinimumProtocolVersion: tls.TlsParameters_TLSv1_2,
},
},
}),
},
},
Filters: []*listener.Filter{{Name: "envoy.transport_sockets.tls"}},
},
{
Filters: []*listener.Filter{
{Name: "filter0"},
{Name: "filter1"},
},
},
},
},
{
Name: "another-listener",
},
}
faultFilterIn := &fault.HTTPFault{
UpstreamCluster: "foobar",
}
faultFilterInAny, _ := anypb.New(faultFilterIn)
faultFilterOut := &fault.HTTPFault{
UpstreamCluster: "scooby",
DownstreamNodes: []string{"foo"},
}
faultFilterOutAny, _ := anypb.New(faultFilterOut)
gatewayIn := []*listener.Listener{
{
Name: "80",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 80,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{
ServerNames: []string{"match.com", "*.foo.com"},
},
Filters: []*listener.Filter{
{
Name: wellknown.HTTPConnectionManager,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&http_conn.HttpConnectionManager{
HttpFilters: []*http_conn.HttpFilter{
{Name: "http-filter1"},
{Name: "http-filter2"},
},
}),
},
},
},
},
},
},
{
Name: "another-listener",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 443,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{
ServerNames: []string{"nomatch.com", "*.foo.com"},
},
Filters: []*listener.Filter{{Name: "network-filter"}},
},
},
},
}
gatewayOut := []*listener.Listener{
{
Name: "80",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 80,
},
},
},
},
ListenerFilters: []*listener.ListenerFilter{{Name: "foo"}},
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{
ServerNames: []string{"match.com", "*.foo.com", "foo.com"},
},
Filters: []*listener.Filter{
{
Name: wellknown.HTTPConnectionManager,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&http_conn.HttpConnectionManager{
HttpFilters: []*http_conn.HttpFilter{
{Name: "http-filter1"},
{Name: "http-filter2"},
{Name: "http-filter3"},
},
}),
},
},
},
},
},
},
{
Name: "another-listener",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 443,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
FilterChainMatch: &listener.FilterChainMatch{
ServerNames: []string{"nomatch.com", "*.foo.com"},
},
Filters: []*listener.Filter{{Name: "network-filter"}},
},
},
},
}
sidecarVirtualInboundIn := []*listener.Listener{
{
Name: model.VirtualInboundListenerName,
UseOriginalDst: istio_proto.BoolTrue,
TrafficDirection: core.TrafficDirection_INBOUND,
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 15006,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
Name: "virtualInbound-blackhole",
FilterChainMatch: &listener.FilterChainMatch{
DestinationPort: &wrappers.UInt32Value{
Value: 15006,
},
},
Filters: []*listener.Filter{
{
Name: wellknown.TCPProxy,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&tcp_proxy.TcpProxy{
StatPrefix: util.BlackHoleCluster,
ClusterSpecifier: &tcp_proxy.TcpProxy_Cluster{Cluster: util.BlackHoleCluster},
}),
},
},
},
},
{
FilterChainMatch: &listener.FilterChainMatch{
DestinationPort: &wrapperspb.UInt32Value{
Value: 80,
},
},
Filters: []*listener.Filter{
{
Name: wellknown.HTTPConnectionManager,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&http_conn.HttpConnectionManager{
HttpFilters: []*http_conn.HttpFilter{
{
Name: wellknown.Fault,
ConfigType: &http_conn.HttpFilter_TypedConfig{TypedConfig: faultFilterInAny},
},
{Name: "http-filter2"},
{Name: "http-filter-to-be-removed"},
},
}),
},
},
},
},
{
FilterChainMatch: &listener.FilterChainMatch{
AddressSuffix: "0.0.0.0",
},
Filters: []*listener.Filter{
{Name: "network-filter-should-not-be-replaced"},
},
},
{
FilterChainMatch: &listener.FilterChainMatch{
DestinationPort: &wrapperspb.UInt32Value{
Value: 6380,
},
},
Filters: []*listener.Filter{
{Name: "network-filter-to-be-replaced"},
},
},
{
Name: "filter-chain-name-not-match",
Filters: []*listener.Filter{
{Name: "custom-network-filter-1"},
{Name: "custom-network-filter-2"},
},
},
{
Name: "filter-chain-name-match",
Filters: []*listener.Filter{
{Name: "custom-network-filter-1"},
{Name: "custom-network-filter-2"},
},
},
{
Name: "catch-all",
FilterChainMatch: &listener.FilterChainMatch{},
Filters: []*listener.Filter{
{
Name: wellknown.HTTPConnectionManager,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&http_conn.HttpConnectionManager{
HttpFilters: []*http_conn.HttpFilter{
{Name: "base"},
},
}),
},
},
},
},
},
},
}
sidecarVirtualInboundOut := []*listener.Listener{
{
Name: model.VirtualInboundListenerName,
UseOriginalDst: istio_proto.BoolTrue,
TrafficDirection: core.TrafficDirection_INBOUND,
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 15006,
},
},
},
},
FilterChains: []*listener.FilterChain{
{
Name: "virtualInbound-blackhole",
FilterChainMatch: &listener.FilterChainMatch{
DestinationPort: &wrappers.UInt32Value{
Value: 15006,
},
},
Filters: []*listener.Filter{
{
Name: wellknown.TCPProxy,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&tcp_proxy.TcpProxy{
StatPrefix: util.BlackHoleCluster,
ClusterSpecifier: &tcp_proxy.TcpProxy_Cluster{Cluster: util.BlackHoleCluster},
}),
},
},
},
},
{
FilterChainMatch: &listener.FilterChainMatch{
DestinationPort: &wrapperspb.UInt32Value{
Value: 80,
},
},
TransportSocket: &core.TransportSocket{
Name: "envoy.transport_sockets.tls",
ConfigType: &core.TransportSocket_TypedConfig{
TypedConfig: util.MessageToAny(&tls.DownstreamTlsContext{
CommonTlsContext: &tls.CommonTlsContext{
AlpnProtocols: []string{"h2-80", "http/1.1-80"},
},
}),
},
},
Filters: []*listener.Filter{
{
Name: wellknown.HTTPConnectionManager,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&http_conn.HttpConnectionManager{
XffNumTrustedHops: 4,
MergeSlashes: true,
AlwaysSetRequestIdInResponse: true,
HttpFilters: []*http_conn.HttpFilter{
{Name: "http-filter0"},
{
Name: wellknown.Fault,
ConfigType: &http_conn.HttpFilter_TypedConfig{TypedConfig: faultFilterOutAny},
},
{Name: "http-filter3"},
{Name: "http-filter2"},
{Name: "http-filter-5"},
{Name: "http-filter4"},
},
}),
},
},
},
},
{
FilterChainMatch: &listener.FilterChainMatch{
AddressSuffix: "0.0.0.0",
},
Filters: []*listener.Filter{
{Name: "network-filter-should-not-be-replaced"},
},
},
{
FilterChainMatch: &listener.FilterChainMatch{
DestinationPort: &wrapperspb.UInt32Value{
Value: 6380,
},
},
TransportSocket: &core.TransportSocket{
Name: "envoy.transport_sockets.tls",
ConfigType: &core.TransportSocket_TypedConfig{
TypedConfig: util.MessageToAny(&tls.DownstreamTlsContext{
CommonTlsContext: &tls.CommonTlsContext{
AlpnProtocols: []string{"h2-6380", "http/1.1-6380"},
},
}),
},
},
Filters: []*listener.Filter{
{
Name: "envoy.redis_proxy",
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&redis.RedisProxy{
StatPrefix: "redis_stats",
PrefixRoutes: &redis.RedisProxy_PrefixRoutes{
CatchAllRoute: &redis.RedisProxy_PrefixRoutes_Route{
Cluster: "custom-redis-cluster",
},
},
}),
},
},
},
},
{
Name: "filter-chain-name-not-match",
Filters: []*listener.Filter{
{Name: "custom-network-filter-1"},
{Name: "custom-network-filter-2"},
},
},
{
Name: "filter-chain-name-match",
Filters: []*listener.Filter{
{Name: "custom-network-filter-1"},
},
},
{
Name: "catch-all",
FilterChainMatch: &listener.FilterChainMatch{},
Filters: []*listener.Filter{
{
Name: wellknown.HTTPConnectionManager,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&http_conn.HttpConnectionManager{
HttpFilters: []*http_conn.HttpFilter{
{Name: "base"},
},
}),
},
},
},
},
},
},
}
sidecarProxy := &model.Proxy{
Type: model.SidecarProxy,
ConfigNamespace: "not-default",
Metadata: &model.NodeMetadata{
IstioVersion: "1.2.2",
Raw: map[string]interface{}{
"foo": "sidecar",
"bar": "proxy",
},
},
}
gatewayProxy := &model.Proxy{
Type: model.Router,
ConfigNamespace: "not-default",
Metadata: &model.NodeMetadata{
IstioVersion: "1.2.2",
Raw: map[string]interface{}{
"foo": "sidecar",
"bar": "proxy",
},
},
}
serviceDiscovery := memregistry.NewServiceDiscovery()
e := newTestEnvironment(serviceDiscovery, testMesh, buildEnvoyFilterConfigStore(configPatches))
push := model.NewPushContext()
_ = push.InitContext(e, nil, nil)
type args struct {
patchContext networking.EnvoyFilter_PatchContext
proxy *model.Proxy
push *model.PushContext
listeners []*listener.Listener
skipAdds bool
}
tests := []struct {
name string
args args
want []*listener.Listener
}{
{
name: "gateway lds",
args: args{
patchContext: networking.EnvoyFilter_GATEWAY,
proxy: gatewayProxy,
push: push,
listeners: gatewayIn,
skipAdds: false,
},
want: gatewayOut,
},
{
name: "sidecar outbound lds",
args: args{
patchContext: networking.EnvoyFilter_SIDECAR_OUTBOUND,
proxy: sidecarProxy,
push: push,
listeners: sidecarOutboundIn,
skipAdds: false,
},
want: sidecarOutboundOut,
},
{
name: "sidecar outbound lds - skip adds",
args: args{
patchContext: networking.EnvoyFilter_SIDECAR_OUTBOUND,
proxy: sidecarProxy,
push: push,
listeners: sidecarOutboundInNoAdd,
skipAdds: true,
},
want: sidecarOutboundOutNoAdd,
},
{
name: "sidecar inbound virtual",
args: args{
patchContext: networking.EnvoyFilter_SIDECAR_INBOUND,
proxy: sidecarProxy,
push: push,
listeners: sidecarVirtualInboundIn,
skipAdds: false,
},
want: sidecarVirtualInboundOut,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ApplyListenerPatches(tt.args.patchContext, tt.args.push.EnvoyFilters(tt.args.proxy),
tt.args.listeners, tt.args.skipAdds)
if diff := cmp.Diff(tt.want, got, protocmp.Transform()); diff != "" {
t.Errorf("ApplyListenerPatches(): %s mismatch (-want +got):\n%s", tt.name, diff)
}
})
}
}
// This benchmark measures the performance of Telemetry V2 EnvoyFilter patches. The intent here is to
// measure overhead of using EnvoyFilters rather than native code.
func BenchmarkTelemetryV2Filters(b *testing.B) {
l := &listener.Listener{
Name: "another-listener",
Address: &core.Address{
Address: &core.Address_SocketAddress{
SocketAddress: &core.SocketAddress{
PortSpecifier: &core.SocketAddress_PortValue{
PortValue: 80,
},
},
},
},
ListenerFilters: []*listener.ListenerFilter{{Name: "envoy.tls_inspector"}},
FilterChains: []*listener.FilterChain{
{
Filters: []*listener.Filter{
{
Name: wellknown.HTTPConnectionManager,
ConfigType: &listener.Filter_TypedConfig{
TypedConfig: util.MessageToAny(&http_conn.HttpConnectionManager{
XffNumTrustedHops: 4,
MergeSlashes: true,
AlwaysSetRequestIdInResponse: true,
HttpFilters: []*http_conn.HttpFilter{
{Name: "http-filter3"},
{Name: "envoy.router"}, // Use deprecated name for test.
{Name: "http-filter2"},
},
}),
},
},
},
},
},
}
file, err := os.ReadFile(filepath.Join(env.IstioSrc, "manifests/charts/istio-control/istio-discovery/files/gen-istio.yaml"))
if err != nil {
b.Fatalf("failed to read telemetry v2 Envoy Filters")
}
var configPatches []*networking.EnvoyFilter_EnvoyConfigObjectPatch
configs, _, err := crd.ParseInputs(string(file))
if err != nil {
b.Fatalf("failed to unmarshal EnvoyFilter: %v", err)
}
for _, c := range configs {
if c.GroupVersionKind != gvk.EnvoyFilter {
continue
}
configPatches = append(configPatches, c.Spec.(*networking.EnvoyFilter).ConfigPatches...)
}
if len(configPatches) == 0 {
b.Fatalf("found no patches, failed to read telemetry config?")
}
sidecarProxy := &model.Proxy{
Type: model.SidecarProxy,
ConfigNamespace: "not-default",
Metadata: &model.NodeMetadata{
IstioVersion: "1.2.2",
Raw: map[string]interface{}{
"foo": "sidecar",
"bar": "proxy",
},
},
}
serviceDiscovery := memregistry.NewServiceDiscovery()
e := newTestEnvironment(serviceDiscovery, testMesh, buildEnvoyFilterConfigStore(configPatches))
push := model.NewPushContext()
_ = push.InitContext(e, nil, nil)
var got interface{}
b.ResetTimer()
for n := 0; n < b.N; n++ {
copied := proto.Clone(l)
got = ApplyListenerPatches(networking.EnvoyFilter_SIDECAR_OUTBOUND, push.EnvoyFilters(sidecarProxy),
[]*listener.Listener{copied.(*listener.Listener)}, false)
}
_ = got
}