istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/networking/core/cluster_traffic_policy_test.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package core
    16  
    17  import (
    18  	"fmt"
    19  	"reflect"
    20  	"testing"
    21  
    22  	cluster "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
    23  	core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    24  	proxyprotocol "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/proxy_protocol/v3"
    25  	tls "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
    26  
    27  	networking "istio.io/api/networking/v1alpha3"
    28  	"istio.io/istio/pilot/pkg/model"
    29  	"istio.io/istio/pilot/pkg/networking/util"
    30  )
    31  
    32  func TestApplyUpstreamProxyProtocol(t *testing.T) {
    33  	istioMutualTLSSettings := &networking.ClientTLSSettings{
    34  		Mode:            networking.ClientTLSSettings_ISTIO_MUTUAL,
    35  		SubjectAltNames: []string{"custom.foo.com"},
    36  		Sni:             "custom.foo.com",
    37  	}
    38  	mutualTLSSettingsWithCerts := &networking.ClientTLSSettings{
    39  		Mode:              networking.ClientTLSSettings_MUTUAL,
    40  		CaCertificates:    "root-cert.pem",
    41  		ClientCertificate: "cert-chain.pem",
    42  		PrivateKey:        "key.pem",
    43  		SubjectAltNames:   []string{"custom.foo.com"},
    44  		Sni:               "custom.foo.com",
    45  	}
    46  	simpleTLSSettingsWithCerts := &networking.ClientTLSSettings{
    47  		Mode:            networking.ClientTLSSettings_SIMPLE,
    48  		CaCertificates:  "root-cert.pem",
    49  		SubjectAltNames: []string{"custom.foo.com"},
    50  		Sni:             "custom.foo.com",
    51  	}
    52  
    53  	tests := []struct {
    54  		name                       string
    55  		mtlsCtx                    mtlsContextType
    56  		discoveryType              cluster.Cluster_DiscoveryType
    57  		tls                        *networking.ClientTLSSettings
    58  		proxyProtocolSettings      *networking.TrafficPolicy_ProxyProtocol
    59  		expectTransportSocket      bool
    60  		expectTransportSocketMatch bool
    61  
    62  		validateTLSContext func(t *testing.T, ctx *tls.UpstreamTlsContext)
    63  	}{
    64  		{
    65  			name:          "user specified without tls",
    66  			mtlsCtx:       userSupplied,
    67  			discoveryType: cluster.Cluster_EDS,
    68  			tls:           nil,
    69  			proxyProtocolSettings: &networking.TrafficPolicy_ProxyProtocol{
    70  				Version: networking.TrafficPolicy_ProxyProtocol_V2,
    71  			},
    72  			expectTransportSocket:      false,
    73  			expectTransportSocketMatch: false,
    74  		},
    75  		{
    76  			name:          "user specified with istio_mutual tls",
    77  			mtlsCtx:       userSupplied,
    78  			discoveryType: cluster.Cluster_EDS,
    79  			tls:           istioMutualTLSSettings,
    80  			proxyProtocolSettings: &networking.TrafficPolicy_ProxyProtocol{
    81  				Version: networking.TrafficPolicy_ProxyProtocol_V2,
    82  			},
    83  			expectTransportSocket:      true,
    84  			expectTransportSocketMatch: false,
    85  			validateTLSContext: func(t *testing.T, ctx *tls.UpstreamTlsContext) {
    86  				if got := ctx.CommonTlsContext.GetAlpnProtocols(); !reflect.DeepEqual(got, util.ALPNInMeshWithMxc) {
    87  					t.Fatalf("expected alpn list %v; got %v", util.ALPNInMeshWithMxc, got)
    88  				}
    89  			},
    90  		},
    91  		{
    92  			name:          "user specified simple tls",
    93  			mtlsCtx:       userSupplied,
    94  			discoveryType: cluster.Cluster_EDS,
    95  			tls:           simpleTLSSettingsWithCerts,
    96  			proxyProtocolSettings: &networking.TrafficPolicy_ProxyProtocol{
    97  				Version: networking.TrafficPolicy_ProxyProtocol_V2,
    98  			},
    99  			expectTransportSocket:      true,
   100  			expectTransportSocketMatch: false,
   101  			validateTLSContext: func(t *testing.T, ctx *tls.UpstreamTlsContext) {
   102  				rootName := "file-root:" + mutualTLSSettingsWithCerts.CaCertificates
   103  				if got := ctx.CommonTlsContext.GetCombinedValidationContext().GetValidationContextSdsSecretConfig().GetName(); rootName != got {
   104  					t.Fatalf("expected root name %v got %v", rootName, got)
   105  				}
   106  				if got := ctx.CommonTlsContext.GetAlpnProtocols(); got != nil {
   107  					t.Fatalf("expected alpn list nil as not h2 or Istio_Mutual TLS Setting; got %v", got)
   108  				}
   109  				if got := ctx.GetSni(); got != simpleTLSSettingsWithCerts.Sni {
   110  					t.Fatalf("expected TLSContext SNI %v; got %v", simpleTLSSettingsWithCerts.Sni, got)
   111  				}
   112  			},
   113  		},
   114  		{
   115  			name:          "user specified mutual tls",
   116  			mtlsCtx:       userSupplied,
   117  			discoveryType: cluster.Cluster_EDS,
   118  			tls:           mutualTLSSettingsWithCerts,
   119  			proxyProtocolSettings: &networking.TrafficPolicy_ProxyProtocol{
   120  				Version: networking.TrafficPolicy_ProxyProtocol_V2,
   121  			},
   122  			expectTransportSocket:      true,
   123  			expectTransportSocketMatch: false,
   124  			validateTLSContext: func(t *testing.T, ctx *tls.UpstreamTlsContext) {
   125  				rootName := "file-root:" + mutualTLSSettingsWithCerts.CaCertificates
   126  				certName := fmt.Sprintf("file-cert:%s~%s", mutualTLSSettingsWithCerts.ClientCertificate, mutualTLSSettingsWithCerts.PrivateKey)
   127  				if got := ctx.CommonTlsContext.GetCombinedValidationContext().GetValidationContextSdsSecretConfig().GetName(); rootName != got {
   128  					t.Fatalf("expected root name %v got %v", rootName, got)
   129  				}
   130  				if got := ctx.CommonTlsContext.GetTlsCertificateSdsSecretConfigs()[0].GetName(); certName != got {
   131  					t.Fatalf("expected cert name %v got %v", certName, got)
   132  				}
   133  				if got := ctx.CommonTlsContext.GetAlpnProtocols(); got != nil {
   134  					t.Fatalf("expected alpn list nil as not h2 or Istio_Mutual TLS Setting; got %v", got)
   135  				}
   136  				if got := ctx.GetSni(); got != mutualTLSSettingsWithCerts.Sni {
   137  					t.Fatalf("expected TLSContext SNI %v; got %v", mutualTLSSettingsWithCerts.Sni, got)
   138  				}
   139  			},
   140  		},
   141  		{
   142  			name:          "auto detect with tls",
   143  			mtlsCtx:       autoDetected,
   144  			discoveryType: cluster.Cluster_EDS,
   145  			tls:           istioMutualTLSSettings,
   146  			proxyProtocolSettings: &networking.TrafficPolicy_ProxyProtocol{
   147  				Version: networking.TrafficPolicy_ProxyProtocol_V2,
   148  			},
   149  			expectTransportSocket:      false,
   150  			expectTransportSocketMatch: true,
   151  			validateTLSContext: func(t *testing.T, ctx *tls.UpstreamTlsContext) {
   152  				if got := ctx.CommonTlsContext.GetAlpnProtocols(); !reflect.DeepEqual(got, util.ALPNInMeshWithMxc) {
   153  					t.Fatalf("expected alpn list %v; got %v", util.ALPNInMeshWithMxc, got)
   154  				}
   155  			},
   156  		},
   157  	}
   158  
   159  	proxy := &model.Proxy{
   160  		Type:         model.SidecarProxy,
   161  		Metadata:     &model.NodeMetadata{},
   162  		IstioVersion: &model.IstioVersion{Major: 1, Minor: 5},
   163  	}
   164  	push := model.NewPushContext()
   165  	for _, test := range tests {
   166  		t.Run(test.name, func(t *testing.T) {
   167  			cb := NewClusterBuilder(proxy, &model.PushRequest{Push: push}, model.DisabledCache{})
   168  			opts := &buildClusterOpts{
   169  				mutable: newClusterWrapper(&cluster.Cluster{
   170  					ClusterDiscoveryType: &cluster.Cluster_Type{Type: test.discoveryType},
   171  				}),
   172  				mesh: push.Mesh,
   173  			}
   174  			cb.applyUpstreamTLSSettings(opts, test.tls, test.mtlsCtx)
   175  			// apply proxy protocol settings
   176  			cb.applyUpstreamProxyProtocol(opts, test.proxyProtocolSettings)
   177  			cluster := opts.mutable.cluster
   178  			if test.expectTransportSocket && cluster.TransportSocket == nil ||
   179  				!test.expectTransportSocket && cluster.TransportSocket != nil {
   180  				t.Errorf("Expected TransportSocket %v", test.expectTransportSocket)
   181  			}
   182  			if test.expectTransportSocketMatch && cluster.TransportSocketMatches == nil ||
   183  				!test.expectTransportSocketMatch && cluster.TransportSocketMatches != nil {
   184  				t.Errorf("Expected TransportSocketMatch %v", test.expectTransportSocketMatch)
   185  			}
   186  			upstreamProxyProtocol := &proxyprotocol.ProxyProtocolUpstreamTransport{}
   187  			if cluster.TransportSocket != nil {
   188  				if got := cluster.TransportSocket.Name; got != "envoy.transport_sockets.upstream_proxy_protocol" {
   189  					t.Errorf("Expected TransportSocket name %v, got %v", "envoy.transport_sockets.upstream_proxy_protocol", got)
   190  				}
   191  				if err := cluster.TransportSocket.GetTypedConfig().UnmarshalTo(upstreamProxyProtocol); err != nil {
   192  					t.Fatal(err)
   193  				}
   194  				if upstreamProxyProtocol.Config.Version != core.ProxyProtocolConfig_Version(test.proxyProtocolSettings.Version) {
   195  					t.Errorf("Expected proxy protocol version %v, got %v", test.proxyProtocolSettings.Version, upstreamProxyProtocol.Config.Version)
   196  				}
   197  				if test.validateTLSContext != nil {
   198  					ctx := &tls.UpstreamTlsContext{}
   199  					if err := upstreamProxyProtocol.TransportSocket.GetTypedConfig().UnmarshalTo(ctx); err != nil {
   200  						t.Fatal(err)
   201  					}
   202  				}
   203  			}
   204  
   205  			for i, match := range cluster.TransportSocketMatches {
   206  				if err := match.TransportSocket.GetTypedConfig().UnmarshalTo(upstreamProxyProtocol); err != nil {
   207  					t.Fatal(err)
   208  				}
   209  				if upstreamProxyProtocol.Config.Version != core.ProxyProtocolConfig_Version(test.proxyProtocolSettings.Version) {
   210  					t.Errorf("Expected proxy protocol version %v, got %v", test.proxyProtocolSettings.Version, upstreamProxyProtocol.Config.Version)
   211  				}
   212  				if test.validateTLSContext != nil && i == 0 {
   213  					ctx := &tls.UpstreamTlsContext{}
   214  					if err := upstreamProxyProtocol.TransportSocket.GetTypedConfig().UnmarshalTo(ctx); err != nil {
   215  						t.Fatal(err)
   216  					}
   217  				}
   218  			}
   219  		})
   220  	}
   221  }