1
17
18 package xdsresource
19
20 import (
21 "encoding/json"
22 "regexp"
23 "strings"
24 "testing"
25
26 "github.com/google/go-cmp/cmp"
27 "github.com/google/go-cmp/cmp/cmpopts"
28 "google.golang.org/grpc/internal/pretty"
29 "google.golang.org/grpc/internal/testutils"
30 "google.golang.org/grpc/internal/xds/bootstrap"
31 "google.golang.org/grpc/internal/xds/matcher"
32 "google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version"
33
34 v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
35 v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
36 v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
37 v3aggregateclusterpb "github.com/envoyproxy/go-control-plane/envoy/extensions/clusters/aggregate/v3"
38 v3leastrequestpb "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/least_request/v3"
39 v3ringhashpb "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/ring_hash/v3"
40 v3tlspb "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
41 v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
42 v3matcherpb "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
43 "google.golang.org/protobuf/types/known/anypb"
44 "google.golang.org/protobuf/types/known/durationpb"
45 "google.golang.org/protobuf/types/known/structpb"
46 "google.golang.org/protobuf/types/known/wrapperspb"
47 )
48
49 const (
50 clusterName = "clusterName"
51 serviceName = "service"
52 )
53
54 func (s) TestValidateCluster_Failure(t *testing.T) {
55 tests := []struct {
56 name string
57 cluster *v3clusterpb.Cluster
58 wantErr bool
59 }{
60 {
61 name: "non-supported-cluster-type-static",
62 cluster: &v3clusterpb.Cluster{
63 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_STATIC},
64 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
65 EdsConfig: &v3corepb.ConfigSource{
66 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
67 Ads: &v3corepb.AggregatedConfigSource{},
68 },
69 },
70 },
71 LbPolicy: v3clusterpb.Cluster_LEAST_REQUEST,
72 },
73 wantErr: true,
74 },
75 {
76 name: "non-supported-cluster-type-original-dst",
77 cluster: &v3clusterpb.Cluster{
78 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_ORIGINAL_DST},
79 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
80 EdsConfig: &v3corepb.ConfigSource{
81 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
82 Ads: &v3corepb.AggregatedConfigSource{},
83 },
84 },
85 },
86 LbPolicy: v3clusterpb.Cluster_LEAST_REQUEST,
87 },
88 wantErr: true,
89 },
90 {
91 name: "no-eds-config",
92 cluster: &v3clusterpb.Cluster{
93 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
94 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
95 },
96 wantErr: true,
97 },
98 {
99 name: "no-ads-config-source",
100 cluster: &v3clusterpb.Cluster{
101 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
102 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{},
103 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
104 },
105 wantErr: true,
106 },
107 {
108 name: "non-round-robin-or-ring-hash-lb-policy",
109 cluster: &v3clusterpb.Cluster{
110 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
111 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
112 EdsConfig: &v3corepb.ConfigSource{
113 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
114 Ads: &v3corepb.AggregatedConfigSource{},
115 },
116 },
117 },
118 LbPolicy: v3clusterpb.Cluster_LEAST_REQUEST,
119 },
120 wantErr: true,
121 },
122 {
123 name: "logical-dns-multiple-localities",
124 cluster: &v3clusterpb.Cluster{
125 Name: clusterName,
126 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_LOGICAL_DNS},
127 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
128 LoadAssignment: &v3endpointpb.ClusterLoadAssignment{
129 Endpoints: []*v3endpointpb.LocalityLbEndpoints{
130
131 {LbEndpoints: nil},
132 {LbEndpoints: nil},
133 },
134 },
135 },
136 wantErr: true,
137 },
138 {
139 name: "ring-hash-hash-function-not-xx-hash",
140 cluster: &v3clusterpb.Cluster{
141 LbPolicy: v3clusterpb.Cluster_RING_HASH,
142 LbConfig: &v3clusterpb.Cluster_RingHashLbConfig_{
143 RingHashLbConfig: &v3clusterpb.Cluster_RingHashLbConfig{
144 HashFunction: v3clusterpb.Cluster_RingHashLbConfig_MURMUR_HASH_2,
145 },
146 },
147 },
148 wantErr: true,
149 },
150 {
151 name: "least-request-choice-count-less-than-two",
152 cluster: &v3clusterpb.Cluster{
153 LbPolicy: v3clusterpb.Cluster_RING_HASH,
154 LbConfig: &v3clusterpb.Cluster_LeastRequestLbConfig_{
155 LeastRequestLbConfig: &v3clusterpb.Cluster_LeastRequestLbConfig{
156 ChoiceCount: wrapperspb.UInt32(1),
157 },
158 },
159 },
160 wantErr: true,
161 },
162 {
163 name: "ring-hash-max-bound-greater-than-upper-bound",
164 cluster: &v3clusterpb.Cluster{
165 LbPolicy: v3clusterpb.Cluster_RING_HASH,
166 LbConfig: &v3clusterpb.Cluster_RingHashLbConfig_{
167 RingHashLbConfig: &v3clusterpb.Cluster_RingHashLbConfig{
168 MaximumRingSize: wrapperspb.UInt64(ringHashSizeUpperBound + 1),
169 },
170 },
171 },
172 wantErr: true,
173 },
174 {
175 name: "ring-hash-max-bound-greater-than-upper-bound-load-balancing-policy",
176 cluster: &v3clusterpb.Cluster{
177 Name: clusterName,
178 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
179 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
180 EdsConfig: &v3corepb.ConfigSource{
181 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
182 Ads: &v3corepb.AggregatedConfigSource{},
183 },
184 },
185 ServiceName: serviceName,
186 },
187 LoadBalancingPolicy: &v3clusterpb.LoadBalancingPolicy{
188 Policies: []*v3clusterpb.LoadBalancingPolicy_Policy{
189 {
190 TypedExtensionConfig: &v3corepb.TypedExtensionConfig{
191 TypedConfig: testutils.MarshalAny(t, &v3ringhashpb.RingHash{
192 HashFunction: v3ringhashpb.RingHash_XX_HASH,
193 MinimumRingSize: wrapperspb.UInt64(10),
194 MaximumRingSize: wrapperspb.UInt64(ringHashSizeUpperBound + 1),
195 }),
196 },
197 },
198 },
199 },
200 },
201 wantErr: true,
202 },
203 {
204 name: "least-request-unsupported-in-converter-since-env-var-unset",
205 cluster: &v3clusterpb.Cluster{
206 Name: clusterName,
207 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
208 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
209 EdsConfig: &v3corepb.ConfigSource{
210 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
211 Ads: &v3corepb.AggregatedConfigSource{},
212 },
213 },
214 ServiceName: serviceName,
215 },
216 LoadBalancingPolicy: &v3clusterpb.LoadBalancingPolicy{
217 Policies: []*v3clusterpb.LoadBalancingPolicy_Policy{
218 {
219 TypedExtensionConfig: &v3corepb.TypedExtensionConfig{
220 TypedConfig: testutils.MarshalAny(t, &v3leastrequestpb.LeastRequest{}),
221 },
222 },
223 },
224 },
225 },
226 wantErr: true,
227 },
228 {
229 name: "aggregate-nil-clusters",
230 cluster: &v3clusterpb.Cluster{
231 Name: clusterName,
232 ClusterDiscoveryType: &v3clusterpb.Cluster_ClusterType{
233 ClusterType: &v3clusterpb.Cluster_CustomClusterType{
234 Name: "envoy.clusters.aggregate",
235 TypedConfig: testutils.MarshalAny(t, &v3aggregateclusterpb.ClusterConfig{}),
236 },
237 },
238 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
239 },
240 wantErr: true,
241 },
242 {
243 name: "aggregate-empty-clusters",
244 cluster: &v3clusterpb.Cluster{
245 Name: clusterName,
246 ClusterDiscoveryType: &v3clusterpb.Cluster_ClusterType{
247 ClusterType: &v3clusterpb.Cluster_CustomClusterType{
248 Name: "envoy.clusters.aggregate",
249 TypedConfig: testutils.MarshalAny(t, &v3aggregateclusterpb.ClusterConfig{
250 Clusters: []string{},
251 }),
252 },
253 },
254 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
255 },
256 wantErr: true,
257 },
258 }
259
260 for _, test := range tests {
261 t.Run(test.name, func(t *testing.T) {
262 if update, err := validateClusterAndConstructClusterUpdate(test.cluster, nil); err == nil {
263 t.Errorf("validateClusterAndConstructClusterUpdate(%+v) = %v, wanted error", test.cluster, update)
264 }
265 })
266 }
267 }
268
269 func (s) TestSecurityConfigFromCommonTLSContextUsingNewFields_ErrorCases(t *testing.T) {
270 tests := []struct {
271 name string
272 common *v3tlspb.CommonTlsContext
273 server bool
274 wantErr string
275 }{
276 {
277 name: "unsupported-tls_certificates-field-for-identity-certs",
278 common: &v3tlspb.CommonTlsContext{
279 TlsCertificates: []*v3tlspb.TlsCertificate{
280 {CertificateChain: &v3corepb.DataSource{}},
281 },
282 },
283 wantErr: "unsupported field tls_certificates is set in CommonTlsContext message",
284 },
285 {
286 name: "unsupported-tls_certificates_sds_secret_configs-field-for-identity-certs",
287 common: &v3tlspb.CommonTlsContext{
288 TlsCertificateSdsSecretConfigs: []*v3tlspb.SdsSecretConfig{
289 {Name: "sds-secrets-config"},
290 },
291 },
292 wantErr: "unsupported field tls_certificate_sds_secret_configs is set in CommonTlsContext message",
293 },
294 {
295 name: "unsupported-sds-validation-context",
296 common: &v3tlspb.CommonTlsContext{
297 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContextSdsSecretConfig{
298 ValidationContextSdsSecretConfig: &v3tlspb.SdsSecretConfig{
299 Name: "foo-sds-secret",
300 },
301 },
302 },
303 wantErr: "validation context contains unexpected type",
304 },
305 {
306 name: "missing-ca_certificate_provider_instance-in-validation-context",
307 common: &v3tlspb.CommonTlsContext{
308 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
309 ValidationContext: &v3tlspb.CertificateValidationContext{},
310 },
311 },
312 wantErr: "expected field ca_certificate_provider_instance is missing in CommonTlsContext message",
313 },
314 {
315 name: "unsupported-field-verify_certificate_spki-in-validation-context",
316 common: &v3tlspb.CommonTlsContext{
317 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
318 ValidationContext: &v3tlspb.CertificateValidationContext{
319 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
320 InstanceName: "rootPluginInstance",
321 CertificateName: "rootCertName",
322 },
323 VerifyCertificateSpki: []string{"spki"},
324 },
325 },
326 },
327 wantErr: "unsupported verify_certificate_spki field in CommonTlsContext message",
328 },
329 {
330 name: "unsupported-field-verify_certificate_hash-in-validation-context",
331 common: &v3tlspb.CommonTlsContext{
332 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
333 ValidationContext: &v3tlspb.CertificateValidationContext{
334 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
335 InstanceName: "rootPluginInstance",
336 CertificateName: "rootCertName",
337 },
338 VerifyCertificateHash: []string{"hash"},
339 },
340 },
341 },
342 wantErr: "unsupported verify_certificate_hash field in CommonTlsContext message",
343 },
344 {
345 name: "unsupported-field-require_signed_certificate_timestamp-in-validation-context",
346 common: &v3tlspb.CommonTlsContext{
347 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
348 ValidationContext: &v3tlspb.CertificateValidationContext{
349 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
350 InstanceName: "rootPluginInstance",
351 CertificateName: "rootCertName",
352 },
353 RequireSignedCertificateTimestamp: &wrapperspb.BoolValue{Value: true},
354 },
355 },
356 },
357 wantErr: "unsupported require_sugned_ceritificate_timestamp field in CommonTlsContext message",
358 },
359 {
360 name: "unsupported-field-crl-in-validation-context",
361 common: &v3tlspb.CommonTlsContext{
362 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
363 ValidationContext: &v3tlspb.CertificateValidationContext{
364 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
365 InstanceName: "rootPluginInstance",
366 CertificateName: "rootCertName",
367 },
368 Crl: &v3corepb.DataSource{},
369 },
370 },
371 },
372 wantErr: "unsupported crl field in CommonTlsContext message",
373 },
374 {
375 name: "unsupported-field-custom_validator_config-in-validation-context",
376 common: &v3tlspb.CommonTlsContext{
377 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
378 ValidationContext: &v3tlspb.CertificateValidationContext{
379 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
380 InstanceName: "rootPluginInstance",
381 CertificateName: "rootCertName",
382 },
383 CustomValidatorConfig: &v3corepb.TypedExtensionConfig{},
384 },
385 },
386 },
387 wantErr: "unsupported custom_validator_config field in CommonTlsContext message",
388 },
389 {
390 name: "invalid-match_subject_alt_names-field-in-validation-context",
391 common: &v3tlspb.CommonTlsContext{
392 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
393 ValidationContext: &v3tlspb.CertificateValidationContext{
394 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
395 InstanceName: "rootPluginInstance",
396 CertificateName: "rootCertName",
397 },
398 MatchSubjectAltNames: []*v3matcherpb.StringMatcher{
399 {MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: ""}},
400 },
401 },
402 },
403 },
404 wantErr: "empty prefix is not allowed in StringMatcher",
405 },
406 {
407 name: "unsupported-field-matching-subject-alt-names-in-validation-context-of-server",
408 common: &v3tlspb.CommonTlsContext{
409 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
410 ValidationContext: &v3tlspb.CertificateValidationContext{
411 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
412 InstanceName: "rootPluginInstance",
413 CertificateName: "rootCertName",
414 },
415 MatchSubjectAltNames: []*v3matcherpb.StringMatcher{
416 {MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "sanPrefix"}},
417 },
418 },
419 },
420 },
421 server: true,
422 wantErr: "match_subject_alt_names field in validation context is not supported on the server",
423 },
424 }
425
426 for _, test := range tests {
427 t.Run(test.name, func(t *testing.T) {
428 _, err := securityConfigFromCommonTLSContextUsingNewFields(test.common, test.server)
429 if err == nil {
430 t.Fatal("securityConfigFromCommonTLSContextUsingNewFields() succeeded when expected to fail")
431 }
432 if !strings.Contains(err.Error(), test.wantErr) {
433 t.Fatalf("securityConfigFromCommonTLSContextUsingNewFields() returned err: %v, wantErr: %v", err, test.wantErr)
434 }
435 })
436 }
437 }
438
439 func (s) TestValidateClusterWithSecurityConfig(t *testing.T) {
440 const (
441 identityPluginInstance = "identityPluginInstance"
442 identityCertName = "identityCert"
443 rootPluginInstance = "rootPluginInstance"
444 rootCertName = "rootCert"
445 clusterName = "cluster"
446 serviceName = "service"
447 sanExact = "san-exact"
448 sanPrefix = "san-prefix"
449 sanSuffix = "san-suffix"
450 sanRegexBad = "??"
451 sanRegexGood = "san?regex?"
452 sanContains = "san-contains"
453 )
454 var sanRE = regexp.MustCompile(sanRegexGood)
455
456 tests := []struct {
457 name string
458 cluster *v3clusterpb.Cluster
459 wantUpdate ClusterUpdate
460 wantErr bool
461 }{
462 {
463 name: "transport-socket-matches",
464 cluster: &v3clusterpb.Cluster{
465 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
466 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
467 EdsConfig: &v3corepb.ConfigSource{
468 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
469 Ads: &v3corepb.AggregatedConfigSource{},
470 },
471 },
472 ServiceName: serviceName,
473 },
474 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
475 TransportSocketMatches: []*v3clusterpb.Cluster_TransportSocketMatch{
476 {Name: "transport-socket-match-1"},
477 },
478 },
479 wantErr: true,
480 },
481 {
482 name: "transport-socket-unsupported-name",
483 cluster: &v3clusterpb.Cluster{
484 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
485 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
486 EdsConfig: &v3corepb.ConfigSource{
487 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
488 Ads: &v3corepb.AggregatedConfigSource{},
489 },
490 },
491 ServiceName: serviceName,
492 },
493 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
494 TransportSocket: &v3corepb.TransportSocket{
495 Name: "unsupported-foo",
496 ConfigType: &v3corepb.TransportSocket_TypedConfig{
497 TypedConfig: &anypb.Any{
498 TypeUrl: version.V3UpstreamTLSContextURL,
499 },
500 },
501 },
502 },
503 wantErr: true,
504 },
505 {
506 name: "transport-socket-unsupported-typeURL",
507 cluster: &v3clusterpb.Cluster{
508 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
509 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
510 EdsConfig: &v3corepb.ConfigSource{
511 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
512 Ads: &v3corepb.AggregatedConfigSource{},
513 },
514 },
515 ServiceName: serviceName,
516 },
517 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
518 TransportSocket: &v3corepb.TransportSocket{
519 ConfigType: &v3corepb.TransportSocket_TypedConfig{
520 TypedConfig: &anypb.Any{
521 TypeUrl: version.V3HTTPConnManagerURL,
522 },
523 },
524 },
525 },
526 wantErr: true,
527 },
528 {
529 name: "transport-socket-unsupported-type",
530 cluster: &v3clusterpb.Cluster{
531 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
532 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
533 EdsConfig: &v3corepb.ConfigSource{
534 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
535 Ads: &v3corepb.AggregatedConfigSource{},
536 },
537 },
538 ServiceName: serviceName,
539 },
540 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
541 TransportSocket: &v3corepb.TransportSocket{
542 ConfigType: &v3corepb.TransportSocket_TypedConfig{
543 TypedConfig: &anypb.Any{
544 TypeUrl: version.V3UpstreamTLSContextURL,
545 Value: []byte{1, 2, 3, 4},
546 },
547 },
548 },
549 },
550 wantErr: true,
551 },
552 {
553 name: "transport-socket-unsupported-tls-params-field",
554 cluster: &v3clusterpb.Cluster{
555 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
556 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
557 EdsConfig: &v3corepb.ConfigSource{
558 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
559 Ads: &v3corepb.AggregatedConfigSource{},
560 },
561 },
562 ServiceName: serviceName,
563 },
564 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
565 TransportSocket: &v3corepb.TransportSocket{
566 ConfigType: &v3corepb.TransportSocket_TypedConfig{
567 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
568 CommonTlsContext: &v3tlspb.CommonTlsContext{
569 TlsParams: &v3tlspb.TlsParameters{},
570 },
571 }),
572 },
573 },
574 },
575 wantErr: true,
576 },
577 {
578 name: "transport-socket-unsupported-custom-handshaker-field",
579 cluster: &v3clusterpb.Cluster{
580 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
581 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
582 EdsConfig: &v3corepb.ConfigSource{
583 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
584 Ads: &v3corepb.AggregatedConfigSource{},
585 },
586 },
587 ServiceName: serviceName,
588 },
589 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
590 TransportSocket: &v3corepb.TransportSocket{
591 ConfigType: &v3corepb.TransportSocket_TypedConfig{
592 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
593 CommonTlsContext: &v3tlspb.CommonTlsContext{
594 CustomHandshaker: &v3corepb.TypedExtensionConfig{},
595 },
596 }),
597 },
598 },
599 },
600 wantErr: true,
601 },
602 {
603 name: "transport-socket-unsupported-validation-context",
604 cluster: &v3clusterpb.Cluster{
605 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
606 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
607 EdsConfig: &v3corepb.ConfigSource{
608 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
609 Ads: &v3corepb.AggregatedConfigSource{},
610 },
611 },
612 ServiceName: serviceName,
613 },
614 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
615 TransportSocket: &v3corepb.TransportSocket{
616 ConfigType: &v3corepb.TransportSocket_TypedConfig{
617 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
618 CommonTlsContext: &v3tlspb.CommonTlsContext{
619 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContextSdsSecretConfig{
620 ValidationContextSdsSecretConfig: &v3tlspb.SdsSecretConfig{
621 Name: "foo-sds-secret",
622 },
623 },
624 },
625 }),
626 },
627 },
628 },
629 wantErr: true,
630 },
631 {
632 name: "transport-socket-without-validation-context",
633 cluster: &v3clusterpb.Cluster{
634 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
635 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
636 EdsConfig: &v3corepb.ConfigSource{
637 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
638 Ads: &v3corepb.AggregatedConfigSource{},
639 },
640 },
641 ServiceName: serviceName,
642 },
643 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
644 TransportSocket: &v3corepb.TransportSocket{
645 ConfigType: &v3corepb.TransportSocket_TypedConfig{
646 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
647 CommonTlsContext: &v3tlspb.CommonTlsContext{},
648 }),
649 },
650 },
651 },
652 wantErr: true,
653 },
654 {
655 name: "empty-prefix-in-matching-SAN",
656 cluster: &v3clusterpb.Cluster{
657 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
658 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
659 EdsConfig: &v3corepb.ConfigSource{
660 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
661 Ads: &v3corepb.AggregatedConfigSource{},
662 },
663 },
664 ServiceName: serviceName,
665 },
666 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
667 TransportSocket: &v3corepb.TransportSocket{
668 ConfigType: &v3corepb.TransportSocket_TypedConfig{
669 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
670 CommonTlsContext: &v3tlspb.CommonTlsContext{
671 ValidationContextType: &v3tlspb.CommonTlsContext_CombinedValidationContext{
672 CombinedValidationContext: &v3tlspb.CommonTlsContext_CombinedCertificateValidationContext{
673 DefaultValidationContext: &v3tlspb.CertificateValidationContext{
674 MatchSubjectAltNames: []*v3matcherpb.StringMatcher{
675 {MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: ""}},
676 },
677 },
678 ValidationContextCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{
679 InstanceName: rootPluginInstance,
680 CertificateName: rootCertName,
681 },
682 },
683 },
684 },
685 }),
686 },
687 },
688 },
689 wantErr: true,
690 },
691 {
692 name: "empty-suffix-in-matching-SAN",
693 cluster: &v3clusterpb.Cluster{
694 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
695 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
696 EdsConfig: &v3corepb.ConfigSource{
697 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
698 Ads: &v3corepb.AggregatedConfigSource{},
699 },
700 },
701 ServiceName: serviceName,
702 },
703 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
704 TransportSocket: &v3corepb.TransportSocket{
705 ConfigType: &v3corepb.TransportSocket_TypedConfig{
706 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
707 CommonTlsContext: &v3tlspb.CommonTlsContext{
708 ValidationContextType: &v3tlspb.CommonTlsContext_CombinedValidationContext{
709 CombinedValidationContext: &v3tlspb.CommonTlsContext_CombinedCertificateValidationContext{
710 DefaultValidationContext: &v3tlspb.CertificateValidationContext{
711 MatchSubjectAltNames: []*v3matcherpb.StringMatcher{
712 {MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: ""}},
713 },
714 },
715 ValidationContextCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{
716 InstanceName: rootPluginInstance,
717 CertificateName: rootCertName,
718 },
719 },
720 },
721 },
722 }),
723 },
724 },
725 },
726 wantErr: true,
727 },
728 {
729 name: "empty-contains-in-matching-SAN",
730 cluster: &v3clusterpb.Cluster{
731 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
732 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
733 EdsConfig: &v3corepb.ConfigSource{
734 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
735 Ads: &v3corepb.AggregatedConfigSource{},
736 },
737 },
738 ServiceName: serviceName,
739 },
740 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
741 TransportSocket: &v3corepb.TransportSocket{
742 ConfigType: &v3corepb.TransportSocket_TypedConfig{
743 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
744 CommonTlsContext: &v3tlspb.CommonTlsContext{
745 ValidationContextType: &v3tlspb.CommonTlsContext_CombinedValidationContext{
746 CombinedValidationContext: &v3tlspb.CommonTlsContext_CombinedCertificateValidationContext{
747 DefaultValidationContext: &v3tlspb.CertificateValidationContext{
748 MatchSubjectAltNames: []*v3matcherpb.StringMatcher{
749 {MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: ""}},
750 },
751 },
752 ValidationContextCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{
753 InstanceName: rootPluginInstance,
754 CertificateName: rootCertName,
755 },
756 },
757 },
758 },
759 }),
760 },
761 },
762 },
763 wantErr: true,
764 },
765 {
766 name: "invalid-regex-in-matching-SAN",
767 cluster: &v3clusterpb.Cluster{
768 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
769 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
770 EdsConfig: &v3corepb.ConfigSource{
771 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
772 Ads: &v3corepb.AggregatedConfigSource{},
773 },
774 },
775 ServiceName: serviceName,
776 },
777 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
778 TransportSocket: &v3corepb.TransportSocket{
779 ConfigType: &v3corepb.TransportSocket_TypedConfig{
780 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
781 CommonTlsContext: &v3tlspb.CommonTlsContext{
782 ValidationContextType: &v3tlspb.CommonTlsContext_CombinedValidationContext{
783 CombinedValidationContext: &v3tlspb.CommonTlsContext_CombinedCertificateValidationContext{
784 DefaultValidationContext: &v3tlspb.CertificateValidationContext{
785 MatchSubjectAltNames: []*v3matcherpb.StringMatcher{
786 {MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: sanRegexBad}}},
787 },
788 },
789 ValidationContextCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{
790 InstanceName: rootPluginInstance,
791 CertificateName: rootCertName,
792 },
793 },
794 },
795 },
796 }),
797 },
798 },
799 },
800 wantErr: true,
801 },
802 {
803 name: "invalid-regex-in-matching-SAN-with-new-fields",
804 cluster: &v3clusterpb.Cluster{
805 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
806 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
807 EdsConfig: &v3corepb.ConfigSource{
808 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
809 Ads: &v3corepb.AggregatedConfigSource{},
810 },
811 },
812 ServiceName: serviceName,
813 },
814 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
815 TransportSocket: &v3corepb.TransportSocket{
816 ConfigType: &v3corepb.TransportSocket_TypedConfig{
817 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
818 CommonTlsContext: &v3tlspb.CommonTlsContext{
819 ValidationContextType: &v3tlspb.CommonTlsContext_CombinedValidationContext{
820 CombinedValidationContext: &v3tlspb.CommonTlsContext_CombinedCertificateValidationContext{
821 DefaultValidationContext: &v3tlspb.CertificateValidationContext{
822 MatchSubjectAltNames: []*v3matcherpb.StringMatcher{
823 {MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: sanRegexBad}}},
824 },
825 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
826 InstanceName: rootPluginInstance,
827 CertificateName: rootCertName,
828 },
829 },
830 },
831 },
832 },
833 }),
834 },
835 },
836 },
837 wantErr: true,
838 },
839 {
840 name: "happy-case-with-no-identity-certs-using-deprecated-fields",
841 cluster: &v3clusterpb.Cluster{
842 Name: clusterName,
843 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
844 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
845 EdsConfig: &v3corepb.ConfigSource{
846 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
847 Ads: &v3corepb.AggregatedConfigSource{},
848 },
849 },
850 ServiceName: serviceName,
851 },
852 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
853 TransportSocket: &v3corepb.TransportSocket{
854 Name: "envoy.transport_sockets.tls",
855 ConfigType: &v3corepb.TransportSocket_TypedConfig{
856 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
857 CommonTlsContext: &v3tlspb.CommonTlsContext{
858 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContextCertificateProviderInstance{
859 ValidationContextCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{
860 InstanceName: rootPluginInstance,
861 CertificateName: rootCertName,
862 },
863 },
864 },
865 }),
866 },
867 },
868 },
869 wantUpdate: ClusterUpdate{
870 ClusterName: clusterName,
871 EDSServiceName: serviceName,
872 SecurityCfg: &SecurityConfig{
873 RootInstanceName: rootPluginInstance,
874 RootCertName: rootCertName,
875 },
876 },
877 },
878 {
879 name: "happy-case-with-no-identity-certs-using-new-fields",
880 cluster: &v3clusterpb.Cluster{
881 Name: clusterName,
882 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
883 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
884 EdsConfig: &v3corepb.ConfigSource{
885 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
886 Ads: &v3corepb.AggregatedConfigSource{},
887 },
888 },
889 ServiceName: serviceName,
890 },
891 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
892 TransportSocket: &v3corepb.TransportSocket{
893 Name: "envoy.transport_sockets.tls",
894 ConfigType: &v3corepb.TransportSocket_TypedConfig{
895 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
896 CommonTlsContext: &v3tlspb.CommonTlsContext{
897 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
898 ValidationContext: &v3tlspb.CertificateValidationContext{
899 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
900 InstanceName: rootPluginInstance,
901 CertificateName: rootCertName,
902 },
903 },
904 },
905 },
906 }),
907 },
908 },
909 },
910 wantUpdate: ClusterUpdate{
911 ClusterName: clusterName,
912 EDSServiceName: serviceName,
913 SecurityCfg: &SecurityConfig{
914 RootInstanceName: rootPluginInstance,
915 RootCertName: rootCertName,
916 },
917 },
918 },
919 {
920 name: "happy-case-with-validation-context-provider-instance-using-deprecated-fields",
921 cluster: &v3clusterpb.Cluster{
922 Name: clusterName,
923 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
924 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
925 EdsConfig: &v3corepb.ConfigSource{
926 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
927 Ads: &v3corepb.AggregatedConfigSource{},
928 },
929 },
930 ServiceName: serviceName,
931 },
932 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
933 TransportSocket: &v3corepb.TransportSocket{
934 Name: "envoy.transport_sockets.tls",
935 ConfigType: &v3corepb.TransportSocket_TypedConfig{
936 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
937 CommonTlsContext: &v3tlspb.CommonTlsContext{
938 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{
939 InstanceName: identityPluginInstance,
940 CertificateName: identityCertName,
941 },
942 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContextCertificateProviderInstance{
943 ValidationContextCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{
944 InstanceName: rootPluginInstance,
945 CertificateName: rootCertName,
946 },
947 },
948 },
949 }),
950 },
951 },
952 },
953 wantUpdate: ClusterUpdate{
954 ClusterName: clusterName,
955 EDSServiceName: serviceName,
956 SecurityCfg: &SecurityConfig{
957 RootInstanceName: rootPluginInstance,
958 RootCertName: rootCertName,
959 IdentityInstanceName: identityPluginInstance,
960 IdentityCertName: identityCertName,
961 },
962 },
963 },
964 {
965 name: "happy-case-with-validation-context-provider-instance-using-new-fields",
966 cluster: &v3clusterpb.Cluster{
967 Name: clusterName,
968 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
969 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
970 EdsConfig: &v3corepb.ConfigSource{
971 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
972 Ads: &v3corepb.AggregatedConfigSource{},
973 },
974 },
975 ServiceName: serviceName,
976 },
977 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
978 TransportSocket: &v3corepb.TransportSocket{
979 Name: "envoy.transport_sockets.tls",
980 ConfigType: &v3corepb.TransportSocket_TypedConfig{
981 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
982 CommonTlsContext: &v3tlspb.CommonTlsContext{
983 TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
984 InstanceName: identityPluginInstance,
985 CertificateName: identityCertName,
986 },
987 ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
988 ValidationContext: &v3tlspb.CertificateValidationContext{
989 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
990 InstanceName: rootPluginInstance,
991 CertificateName: rootCertName,
992 },
993 },
994 },
995 },
996 }),
997 },
998 },
999 },
1000 wantUpdate: ClusterUpdate{
1001 ClusterName: clusterName,
1002 EDSServiceName: serviceName,
1003 SecurityCfg: &SecurityConfig{
1004 RootInstanceName: rootPluginInstance,
1005 RootCertName: rootCertName,
1006 IdentityInstanceName: identityPluginInstance,
1007 IdentityCertName: identityCertName,
1008 },
1009 },
1010 },
1011 {
1012 name: "happy-case-with-combined-validation-context-using-deprecated-fields",
1013 cluster: &v3clusterpb.Cluster{
1014 Name: clusterName,
1015 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
1016 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
1017 EdsConfig: &v3corepb.ConfigSource{
1018 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
1019 Ads: &v3corepb.AggregatedConfigSource{},
1020 },
1021 },
1022 ServiceName: serviceName,
1023 },
1024 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
1025 TransportSocket: &v3corepb.TransportSocket{
1026 Name: "envoy.transport_sockets.tls",
1027 ConfigType: &v3corepb.TransportSocket_TypedConfig{
1028 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
1029 CommonTlsContext: &v3tlspb.CommonTlsContext{
1030 TlsCertificateCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{
1031 InstanceName: identityPluginInstance,
1032 CertificateName: identityCertName,
1033 },
1034 ValidationContextType: &v3tlspb.CommonTlsContext_CombinedValidationContext{
1035 CombinedValidationContext: &v3tlspb.CommonTlsContext_CombinedCertificateValidationContext{
1036 DefaultValidationContext: &v3tlspb.CertificateValidationContext{
1037 MatchSubjectAltNames: []*v3matcherpb.StringMatcher{
1038 {
1039 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: sanExact},
1040 IgnoreCase: true,
1041 },
1042 {MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: sanPrefix}},
1043 {MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: sanSuffix}},
1044 {MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: sanRegexGood}}},
1045 {MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: sanContains}},
1046 },
1047 },
1048 ValidationContextCertificateProviderInstance: &v3tlspb.CommonTlsContext_CertificateProviderInstance{
1049 InstanceName: rootPluginInstance,
1050 CertificateName: rootCertName,
1051 },
1052 },
1053 },
1054 },
1055 }),
1056 },
1057 },
1058 },
1059 wantUpdate: ClusterUpdate{
1060 ClusterName: clusterName,
1061 EDSServiceName: serviceName,
1062 SecurityCfg: &SecurityConfig{
1063 RootInstanceName: rootPluginInstance,
1064 RootCertName: rootCertName,
1065 IdentityInstanceName: identityPluginInstance,
1066 IdentityCertName: identityCertName,
1067 SubjectAltNameMatchers: []matcher.StringMatcher{
1068 matcher.StringMatcherForTesting(newStringP(sanExact), nil, nil, nil, nil, true),
1069 matcher.StringMatcherForTesting(nil, newStringP(sanPrefix), nil, nil, nil, false),
1070 matcher.StringMatcherForTesting(nil, nil, newStringP(sanSuffix), nil, nil, false),
1071 matcher.StringMatcherForTesting(nil, nil, nil, nil, sanRE, false),
1072 matcher.StringMatcherForTesting(nil, nil, nil, newStringP(sanContains), nil, false),
1073 },
1074 },
1075 },
1076 },
1077 {
1078 name: "happy-case-with-combined-validation-context-using-new-fields",
1079 cluster: &v3clusterpb.Cluster{
1080 Name: clusterName,
1081 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
1082 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
1083 EdsConfig: &v3corepb.ConfigSource{
1084 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
1085 Ads: &v3corepb.AggregatedConfigSource{},
1086 },
1087 },
1088 ServiceName: serviceName,
1089 },
1090 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
1091 TransportSocket: &v3corepb.TransportSocket{
1092 Name: "envoy.transport_sockets.tls",
1093 ConfigType: &v3corepb.TransportSocket_TypedConfig{
1094 TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
1095 CommonTlsContext: &v3tlspb.CommonTlsContext{
1096 TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
1097 InstanceName: identityPluginInstance,
1098 CertificateName: identityCertName,
1099 },
1100 ValidationContextType: &v3tlspb.CommonTlsContext_CombinedValidationContext{
1101 CombinedValidationContext: &v3tlspb.CommonTlsContext_CombinedCertificateValidationContext{
1102 DefaultValidationContext: &v3tlspb.CertificateValidationContext{
1103 MatchSubjectAltNames: []*v3matcherpb.StringMatcher{
1104 {
1105 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: sanExact},
1106 IgnoreCase: true,
1107 },
1108 {MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: sanPrefix}},
1109 {MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: sanSuffix}},
1110 {MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: sanRegexGood}}},
1111 {MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: sanContains}},
1112 },
1113 CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
1114 InstanceName: rootPluginInstance,
1115 CertificateName: rootCertName,
1116 },
1117 },
1118 },
1119 },
1120 },
1121 }),
1122 },
1123 },
1124 },
1125 wantUpdate: ClusterUpdate{
1126 ClusterName: clusterName,
1127 EDSServiceName: serviceName,
1128 SecurityCfg: &SecurityConfig{
1129 RootInstanceName: rootPluginInstance,
1130 RootCertName: rootCertName,
1131 IdentityInstanceName: identityPluginInstance,
1132 IdentityCertName: identityCertName,
1133 SubjectAltNameMatchers: []matcher.StringMatcher{
1134 matcher.StringMatcherForTesting(newStringP(sanExact), nil, nil, nil, nil, true),
1135 matcher.StringMatcherForTesting(nil, newStringP(sanPrefix), nil, nil, nil, false),
1136 matcher.StringMatcherForTesting(nil, nil, newStringP(sanSuffix), nil, nil, false),
1137 matcher.StringMatcherForTesting(nil, nil, nil, nil, sanRE, false),
1138 matcher.StringMatcherForTesting(nil, nil, nil, newStringP(sanContains), nil, false),
1139 },
1140 },
1141 },
1142 },
1143 }
1144
1145 for _, test := range tests {
1146 t.Run(test.name, func(t *testing.T) {
1147 update, err := validateClusterAndConstructClusterUpdate(test.cluster, nil)
1148 if (err != nil) != test.wantErr {
1149 t.Errorf("validateClusterAndConstructClusterUpdate() returned err %v wantErr %v)", err, test.wantErr)
1150 }
1151 if diff := cmp.Diff(test.wantUpdate, update, cmpopts.EquateEmpty(), cmp.AllowUnexported(regexp.Regexp{}), cmpopts.IgnoreFields(ClusterUpdate{}, "LBPolicy")); diff != "" {
1152 t.Errorf("validateClusterAndConstructClusterUpdate() returned unexpected diff (-want, +got):\n%s", diff)
1153 }
1154 })
1155 }
1156 }
1157
1158 func (s) TestUnmarshalCluster(t *testing.T) {
1159 const (
1160 v3ClusterName = "v3clusterName"
1161 v3Service = "v3Service"
1162 )
1163 var (
1164 v3ClusterAny = testutils.MarshalAny(t, &v3clusterpb.Cluster{
1165 Name: v3ClusterName,
1166 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
1167 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
1168 EdsConfig: &v3corepb.ConfigSource{
1169 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
1170 Ads: &v3corepb.AggregatedConfigSource{},
1171 },
1172 },
1173 ServiceName: v3Service,
1174 },
1175 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
1176 LrsServer: &v3corepb.ConfigSource{
1177 ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{
1178 Self: &v3corepb.SelfConfigSource{},
1179 },
1180 },
1181 })
1182
1183 v3ClusterAnyWithEDSConfigSourceSelf = testutils.MarshalAny(t, &v3clusterpb.Cluster{
1184 Name: v3ClusterName,
1185 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
1186 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
1187 EdsConfig: &v3corepb.ConfigSource{
1188 ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{},
1189 },
1190 ServiceName: v3Service,
1191 },
1192 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
1193 LrsServer: &v3corepb.ConfigSource{
1194 ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{
1195 Self: &v3corepb.SelfConfigSource{},
1196 },
1197 },
1198 })
1199
1200 v3ClusterAnyWithTelemetryLabels = testutils.MarshalAny(t, &v3clusterpb.Cluster{
1201 Name: v3ClusterName,
1202 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
1203 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
1204 EdsConfig: &v3corepb.ConfigSource{
1205 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
1206 Ads: &v3corepb.AggregatedConfigSource{},
1207 },
1208 },
1209 ServiceName: v3Service,
1210 },
1211 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
1212 LrsServer: &v3corepb.ConfigSource{
1213 ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{
1214 Self: &v3corepb.SelfConfigSource{},
1215 },
1216 },
1217 Metadata: &v3corepb.Metadata{
1218 FilterMetadata: map[string]*structpb.Struct{
1219 "com.google.csm.telemetry_labels": {
1220 Fields: map[string]*structpb.Value{
1221 "service_name": structpb.NewStringValue("grpc-service"),
1222 "service_namespace": structpb.NewStringValue("grpc-service-namespace"),
1223 },
1224 },
1225 },
1226 },
1227 })
1228 v3ClusterAnyWithTelemetryLabelsIgnoreSome = testutils.MarshalAny(t, &v3clusterpb.Cluster{
1229 Name: v3ClusterName,
1230 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
1231 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
1232 EdsConfig: &v3corepb.ConfigSource{
1233 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
1234 Ads: &v3corepb.AggregatedConfigSource{},
1235 },
1236 },
1237 ServiceName: v3Service,
1238 },
1239 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
1240 LrsServer: &v3corepb.ConfigSource{
1241 ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{
1242 Self: &v3corepb.SelfConfigSource{},
1243 },
1244 },
1245 Metadata: &v3corepb.Metadata{
1246 FilterMetadata: map[string]*structpb.Struct{
1247 "com.google.csm.telemetry_labels": {
1248 Fields: map[string]*structpb.Value{
1249 "string-value-should-ignore": structpb.NewStringValue("string-val"),
1250 "float-value-ignore": structpb.NewNumberValue(3),
1251 "bool-value-ignore": structpb.NewBoolValue(false),
1252 "service_name": structpb.NewStringValue("grpc-service"),
1253 "service_namespace": structpb.NewNullValue(),
1254 },
1255 },
1256 "ignore-this-metadata": {
1257 Fields: map[string]*structpb.Value{
1258 "service_namespace": structpb.NewStringValue("string-val-should-ignore"),
1259 },
1260 },
1261 },
1262 },
1263 })
1264 )
1265
1266 tests := []struct {
1267 name string
1268 resource *anypb.Any
1269 serverCfg *bootstrap.ServerConfig
1270 wantName string
1271 wantUpdate ClusterUpdate
1272 wantErr bool
1273 }{
1274 {
1275 name: "non-cluster resource type",
1276 resource: &anypb.Any{TypeUrl: version.V3HTTPConnManagerURL},
1277 wantErr: true,
1278 },
1279 {
1280 name: "badly marshaled cluster resource",
1281 resource: &anypb.Any{
1282 TypeUrl: version.V3ClusterURL,
1283 Value: []byte{1, 2, 3, 4},
1284 },
1285 wantErr: true,
1286 },
1287 {
1288 name: "bad cluster resource",
1289 resource: testutils.MarshalAny(t, &v3clusterpb.Cluster{
1290 Name: "test",
1291 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_STATIC},
1292 }),
1293 wantName: "test",
1294 wantErr: true,
1295 },
1296 {
1297 name: "cluster resource with non-self lrs_server field",
1298 resource: testutils.MarshalAny(t, &v3clusterpb.Cluster{
1299 Name: "test",
1300 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
1301 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
1302 EdsConfig: &v3corepb.ConfigSource{
1303 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
1304 Ads: &v3corepb.AggregatedConfigSource{},
1305 },
1306 },
1307 ServiceName: v3Service,
1308 },
1309 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
1310 LrsServer: &v3corepb.ConfigSource{
1311 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
1312 Ads: &v3corepb.AggregatedConfigSource{},
1313 },
1314 },
1315 }),
1316 wantName: "test",
1317 wantErr: true,
1318 },
1319 {
1320 name: "v3 cluster",
1321 resource: v3ClusterAny,
1322 serverCfg: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
1323 wantName: v3ClusterName,
1324 wantUpdate: ClusterUpdate{
1325 ClusterName: v3ClusterName,
1326 EDSServiceName: v3Service,
1327 LRSServerConfig: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
1328 Raw: v3ClusterAny,
1329 },
1330 },
1331 {
1332 name: "v3 cluster wrapped",
1333 resource: testutils.MarshalAny(t, &v3discoverypb.Resource{Resource: v3ClusterAny}),
1334 serverCfg: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
1335 wantName: v3ClusterName,
1336 wantUpdate: ClusterUpdate{
1337 ClusterName: v3ClusterName,
1338 EDSServiceName: v3Service,
1339 LRSServerConfig: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
1340 Raw: v3ClusterAny,
1341 },
1342 },
1343 {
1344 name: "v3 cluster with EDS config source self",
1345 resource: v3ClusterAnyWithEDSConfigSourceSelf,
1346 serverCfg: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
1347 wantName: v3ClusterName,
1348 wantUpdate: ClusterUpdate{
1349 ClusterName: v3ClusterName,
1350 EDSServiceName: v3Service,
1351 LRSServerConfig: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
1352 Raw: v3ClusterAnyWithEDSConfigSourceSelf,
1353 },
1354 },
1355 {
1356 name: "v3 cluster with telemetry case",
1357 resource: v3ClusterAnyWithTelemetryLabels,
1358 serverCfg: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
1359 wantName: v3ClusterName,
1360 wantUpdate: ClusterUpdate{
1361 ClusterName: v3ClusterName,
1362 EDSServiceName: v3Service,
1363 LRSServerConfig: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
1364 Raw: v3ClusterAnyWithTelemetryLabels,
1365 TelemetryLabels: map[string]string{
1366 "service_name": "grpc-service",
1367 "service_namespace": "grpc-service-namespace",
1368 },
1369 },
1370 },
1371 {
1372 name: "v3 metadata ignore other types not string and not com.google.csm.telemetry_labels",
1373 resource: v3ClusterAnyWithTelemetryLabelsIgnoreSome,
1374 serverCfg: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
1375 wantName: v3ClusterName,
1376 wantUpdate: ClusterUpdate{
1377 ClusterName: v3ClusterName,
1378 EDSServiceName: v3Service,
1379 LRSServerConfig: &bootstrap.ServerConfig{ServerURI: "test-server-uri"},
1380 Raw: v3ClusterAnyWithTelemetryLabelsIgnoreSome,
1381 TelemetryLabels: map[string]string{
1382 "service_name": "grpc-service",
1383 },
1384 },
1385 },
1386 {
1387 name: "xdstp cluster resource with unset EDS service name",
1388 resource: testutils.MarshalAny(t, &v3clusterpb.Cluster{
1389 Name: "xdstp:foo",
1390 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
1391 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
1392 EdsConfig: &v3corepb.ConfigSource{
1393 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
1394 Ads: &v3corepb.AggregatedConfigSource{},
1395 },
1396 },
1397 ServiceName: "",
1398 },
1399 }),
1400 wantName: "xdstp:foo",
1401 wantErr: true,
1402 },
1403 }
1404 for _, test := range tests {
1405 t.Run(test.name, func(t *testing.T) {
1406 name, update, err := unmarshalClusterResource(test.resource, test.serverCfg)
1407 if (err != nil) != test.wantErr {
1408 t.Fatalf("unmarshalClusterResource(%s), got err: %v, wantErr: %v", pretty.ToJSON(test.resource), err, test.wantErr)
1409 }
1410 if name != test.wantName {
1411 t.Errorf("unmarshalClusterResource(%s), got name: %s, want: %s", pretty.ToJSON(test.resource), name, test.wantName)
1412 }
1413 if diff := cmp.Diff(update, test.wantUpdate, cmpOpts, cmpopts.IgnoreFields(ClusterUpdate{}, "LBPolicy")); diff != "" {
1414 t.Errorf("unmarshalClusterResource(%s), got unexpected update, diff (-got +want): %v", pretty.ToJSON(test.resource), diff)
1415 }
1416 })
1417 }
1418 }
1419
1420 func (s) TestValidateClusterWithOutlierDetection(t *testing.T) {
1421 odToClusterProto := func(od *v3clusterpb.OutlierDetection) *v3clusterpb.Cluster {
1422
1423
1424 return &v3clusterpb.Cluster{
1425 Name: clusterName,
1426 ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS},
1427 EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{
1428 EdsConfig: &v3corepb.ConfigSource{
1429 ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{
1430 Ads: &v3corepb.AggregatedConfigSource{},
1431 },
1432 },
1433 },
1434 LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN,
1435 OutlierDetection: od,
1436 }
1437 }
1438
1439 tests := []struct {
1440 name string
1441 cluster *v3clusterpb.Cluster
1442 wantODCfg string
1443 wantErr bool
1444 }{
1445 {
1446 name: "success-and-failure-null",
1447 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{}),
1448 wantODCfg: `{"successRateEjection": {}}`,
1449 },
1450 {
1451 name: "success-and-failure-zero",
1452 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{
1453 EnforcingSuccessRate: &wrapperspb.UInt32Value{Value: 0},
1454 EnforcingFailurePercentage: &wrapperspb.UInt32Value{Value: 0},
1455 }),
1456 wantODCfg: `{}`,
1457 },
1458 {
1459 name: "some-fields-set",
1460 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{
1461 Interval: &durationpb.Duration{Seconds: 1},
1462 MaxEjectionTime: &durationpb.Duration{Seconds: 3},
1463 EnforcingSuccessRate: &wrapperspb.UInt32Value{Value: 3},
1464 SuccessRateRequestVolume: &wrapperspb.UInt32Value{Value: 5},
1465 EnforcingFailurePercentage: &wrapperspb.UInt32Value{Value: 7},
1466 FailurePercentageRequestVolume: &wrapperspb.UInt32Value{Value: 9},
1467 }),
1468 wantODCfg: `{
1469 "interval": "1s",
1470 "maxEjectionTime": "3s",
1471 "successRateEjection": {
1472 "enforcementPercentage": 3,
1473 "requestVolume": 5
1474 },
1475 "failurePercentageEjection": {
1476 "enforcementPercentage": 7,
1477 "requestVolume": 9
1478 }
1479 }`,
1480 },
1481 {
1482 name: "every-field-set-non-zero",
1483 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{
1484
1485
1486
1487 Interval: &durationpb.Duration{Seconds: 1},
1488 BaseEjectionTime: &durationpb.Duration{Seconds: 2},
1489 MaxEjectionTime: &durationpb.Duration{Seconds: 3},
1490 MaxEjectionPercent: &wrapperspb.UInt32Value{Value: 1},
1491 SuccessRateStdevFactor: &wrapperspb.UInt32Value{Value: 2},
1492 EnforcingSuccessRate: &wrapperspb.UInt32Value{Value: 3},
1493 SuccessRateMinimumHosts: &wrapperspb.UInt32Value{Value: 4},
1494 SuccessRateRequestVolume: &wrapperspb.UInt32Value{Value: 5},
1495 FailurePercentageThreshold: &wrapperspb.UInt32Value{Value: 6},
1496 EnforcingFailurePercentage: &wrapperspb.UInt32Value{Value: 7},
1497 FailurePercentageMinimumHosts: &wrapperspb.UInt32Value{Value: 8},
1498 FailurePercentageRequestVolume: &wrapperspb.UInt32Value{Value: 9},
1499 }),
1500 wantODCfg: `{
1501 "interval": "1s",
1502 "baseEjectionTime": "2s",
1503 "maxEjectionTime": "3s",
1504 "maxEjectionPercent": 1,
1505 "successRateEjection": {
1506 "stdevFactor": 2,
1507 "enforcementPercentage": 3,
1508 "minimumHosts": 4,
1509 "requestVolume": 5
1510 },
1511 "failurePercentageEjection": {
1512 "threshold": 6,
1513 "enforcementPercentage": 7,
1514 "minimumHosts": 8,
1515 "requestVolume": 9
1516 }
1517 }`,
1518 },
1519 {
1520 name: "interval-is-negative",
1521 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{Interval: &durationpb.Duration{Seconds: -10}}),
1522 wantErr: true,
1523 },
1524 {
1525 name: "interval-overflows",
1526 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{Interval: &durationpb.Duration{Seconds: 315576000001}}),
1527 wantErr: true,
1528 },
1529 {
1530 name: "base-ejection-time-is-negative",
1531 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{BaseEjectionTime: &durationpb.Duration{Seconds: -10}}),
1532 wantErr: true,
1533 },
1534 {
1535 name: "base-ejection-time-overflows",
1536 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{BaseEjectionTime: &durationpb.Duration{Seconds: 315576000001}}),
1537 wantErr: true,
1538 },
1539 {
1540 name: "max-ejection-time-is-negative",
1541 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{MaxEjectionTime: &durationpb.Duration{Seconds: -10}}),
1542 wantErr: true,
1543 },
1544 {
1545 name: "max-ejection-time-overflows",
1546 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{MaxEjectionTime: &durationpb.Duration{Seconds: 315576000001}}),
1547 wantErr: true,
1548 },
1549 {
1550 name: "max-ejection-percent-is-greater-than-100",
1551 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{MaxEjectionPercent: &wrapperspb.UInt32Value{Value: 150}}),
1552 wantErr: true,
1553 },
1554 {
1555 name: "enforcing-success-rate-is-greater-than-100",
1556 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{EnforcingSuccessRate: &wrapperspb.UInt32Value{Value: 150}}),
1557 wantErr: true,
1558 },
1559 {
1560 name: "failure-percentage-threshold-is-greater-than-100",
1561 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{FailurePercentageThreshold: &wrapperspb.UInt32Value{Value: 150}}),
1562 wantErr: true,
1563 },
1564 {
1565 name: "enforcing-failure-percentage-is-greater-than-100",
1566 cluster: odToClusterProto(&v3clusterpb.OutlierDetection{EnforcingFailurePercentage: &wrapperspb.UInt32Value{Value: 150}}),
1567 wantErr: true,
1568 },
1569
1570
1571
1572 }
1573 for _, test := range tests {
1574 t.Run(test.name, func(t *testing.T) {
1575 update, err := validateClusterAndConstructClusterUpdate(test.cluster, nil)
1576 if (err != nil) != test.wantErr {
1577 t.Errorf("validateClusterAndConstructClusterUpdate() returned err %v wantErr %v)", err, test.wantErr)
1578 }
1579 if test.wantErr {
1580 return
1581 }
1582
1583
1584 var got map[string]any
1585 if err := json.Unmarshal(update.OutlierDetection, &got); err != nil {
1586 t.Fatalf("Error unmarshalling update.OutlierDetection (%q): %v", update.OutlierDetection, err)
1587 }
1588 var want map[string]any
1589 if err := json.Unmarshal(json.RawMessage(test.wantODCfg), &want); err != nil {
1590 t.Fatalf("Error unmarshalling wantODCfg (%q): %v", test.wantODCfg, err)
1591 }
1592 if diff := cmp.Diff(got, want); diff != "" {
1593 t.Fatalf("cluster.OutlierDetection got unexpected output, diff (-got, +want): %v", diff)
1594 }
1595 })
1596 }
1597 }
1598
View as plain text