...

Source file src/google.golang.org/grpc/test/xds/xds_security_config_nack_test.go

Documentation: google.golang.org/grpc/test/xds

     1  /*
     2   *
     3   * Copyright 2021 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package xds_test
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"testing"
    25  
    26  	"google.golang.org/grpc"
    27  	"google.golang.org/grpc/credentials/insecure"
    28  	xdscreds "google.golang.org/grpc/credentials/xds"
    29  	"google.golang.org/grpc/internal/stubserver"
    30  	"google.golang.org/grpc/internal/testutils"
    31  	"google.golang.org/grpc/internal/testutils/xds/e2e"
    32  
    33  	v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    34  	v3tlspb "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
    35  	testgrpc "google.golang.org/grpc/interop/grpc_testing"
    36  	testpb "google.golang.org/grpc/interop/grpc_testing"
    37  )
    38  
    39  func (s) TestUnmarshalListener_WithUpdateValidatorFunc(t *testing.T) {
    40  	const (
    41  		serviceName                     = "my-service-client-side-xds"
    42  		missingIdentityProviderInstance = "missing-identity-provider-instance"
    43  		missingRootProviderInstance     = "missing-root-provider-instance"
    44  	)
    45  
    46  	tests := []struct {
    47  		name           string
    48  		securityConfig *v3corepb.TransportSocket
    49  		wantErr        bool
    50  	}{
    51  		{
    52  			name: "both identity and root providers are not present in bootstrap",
    53  			securityConfig: &v3corepb.TransportSocket{
    54  				Name: "envoy.transport_sockets.tls",
    55  				ConfigType: &v3corepb.TransportSocket_TypedConfig{
    56  					TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{
    57  						CommonTlsContext: &v3tlspb.CommonTlsContext{
    58  							TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
    59  								InstanceName: missingIdentityProviderInstance,
    60  							},
    61  							ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
    62  								ValidationContext: &v3tlspb.CertificateValidationContext{
    63  									CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
    64  										InstanceName: missingRootProviderInstance,
    65  									},
    66  								},
    67  							},
    68  						},
    69  					}),
    70  				},
    71  			},
    72  			wantErr: true,
    73  		},
    74  		{
    75  			name: "only identity provider is not present in bootstrap",
    76  			securityConfig: &v3corepb.TransportSocket{
    77  				Name: "envoy.transport_sockets.tls",
    78  				ConfigType: &v3corepb.TransportSocket_TypedConfig{
    79  					TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{
    80  						CommonTlsContext: &v3tlspb.CommonTlsContext{
    81  							TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
    82  								InstanceName: missingIdentityProviderInstance,
    83  							},
    84  							ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
    85  								ValidationContext: &v3tlspb.CertificateValidationContext{
    86  									CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
    87  										InstanceName: e2e.ServerSideCertProviderInstance,
    88  									},
    89  								},
    90  							},
    91  						},
    92  					}),
    93  				},
    94  			},
    95  			wantErr: true,
    96  		},
    97  		{
    98  			name: "only root provider is not present in bootstrap",
    99  			securityConfig: &v3corepb.TransportSocket{
   100  				Name: "envoy.transport_sockets.tls",
   101  				ConfigType: &v3corepb.TransportSocket_TypedConfig{
   102  					TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{
   103  						CommonTlsContext: &v3tlspb.CommonTlsContext{
   104  							TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
   105  								InstanceName: e2e.ServerSideCertProviderInstance,
   106  							},
   107  							ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
   108  								ValidationContext: &v3tlspb.CertificateValidationContext{
   109  									CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
   110  										InstanceName: missingRootProviderInstance,
   111  									},
   112  								},
   113  							},
   114  						},
   115  					}),
   116  				},
   117  			},
   118  			wantErr: true,
   119  		},
   120  		{
   121  			name: "both identity and root providers are present in bootstrap",
   122  			securityConfig: &v3corepb.TransportSocket{
   123  				Name: "envoy.transport_sockets.tls",
   124  				ConfigType: &v3corepb.TransportSocket_TypedConfig{
   125  					TypedConfig: testutils.MarshalAny(t, &v3tlspb.DownstreamTlsContext{
   126  						CommonTlsContext: &v3tlspb.CommonTlsContext{
   127  							TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
   128  								InstanceName: e2e.ServerSideCertProviderInstance,
   129  							},
   130  							ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
   131  								ValidationContext: &v3tlspb.CertificateValidationContext{
   132  									CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
   133  										InstanceName: e2e.ServerSideCertProviderInstance,
   134  									},
   135  								},
   136  							},
   137  						},
   138  					}),
   139  				},
   140  			},
   141  			wantErr: false,
   142  		},
   143  	}
   144  
   145  	for _, test := range tests {
   146  		t.Run(test.name, func(t *testing.T) {
   147  			managementServer, nodeID, bootstrapContents, resolver, cleanup1 := e2e.SetupManagementServer(t, e2e.ManagementServerOptions{})
   148  			defer cleanup1()
   149  
   150  			lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
   151  			defer cleanup2()
   152  
   153  			// Grab the host and port of the server and create client side xDS
   154  			// resources corresponding to it.
   155  			host, port, err := hostPortFromListener(lis)
   156  			if err != nil {
   157  				t.Fatalf("failed to retrieve host and port of server: %v", err)
   158  			}
   159  
   160  			// Create xDS resources to be consumed on the client side. This
   161  			// includes the listener, route configuration, cluster (with
   162  			// security configuration) and endpoint resources.
   163  			resources := e2e.DefaultClientResources(e2e.ResourceParams{
   164  				DialTarget: serviceName,
   165  				NodeID:     nodeID,
   166  				Host:       host,
   167  				Port:       port,
   168  				SecLevel:   e2e.SecurityLevelMTLS,
   169  			})
   170  
   171  			// Create an inbound xDS listener resource for the server side.
   172  			inboundLis := e2e.DefaultServerListener(host, port, e2e.SecurityLevelMTLS, "routeName")
   173  			for _, fc := range inboundLis.GetFilterChains() {
   174  				fc.TransportSocket = test.securityConfig
   175  			}
   176  			resources.Listeners = append(resources.Listeners, inboundLis)
   177  
   178  			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   179  			defer cancel()
   180  			if err := managementServer.Update(ctx, resources); err != nil {
   181  				t.Fatal(err)
   182  			}
   183  
   184  			// Create client-side xDS credentials with an insecure fallback.
   185  			creds, err := xdscreds.NewClientCredentials(xdscreds.ClientOptions{FallbackCreds: insecure.NewCredentials()})
   186  			if err != nil {
   187  				t.Fatal(err)
   188  			}
   189  
   190  			// Create a ClientConn with the xds scheme and make an RPC.
   191  			cc, err := grpc.DialContext(ctx, fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(creds), grpc.WithResolvers(resolver))
   192  			if err != nil {
   193  				t.Fatalf("failed to dial local test server: %v", err)
   194  			}
   195  			defer cc.Close()
   196  
   197  			// Make a context with a shorter timeout from the top level test
   198  			// context for cases where we expect failures.
   199  			timeout := defaultTestTimeout
   200  			if test.wantErr {
   201  				timeout = defaultTestShortTimeout
   202  			}
   203  			ctx, cancel = context.WithTimeout(ctx, timeout)
   204  			defer cancel()
   205  			client := testgrpc.NewTestServiceClient(cc)
   206  			if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); (err != nil) != test.wantErr {
   207  				t.Fatalf("EmptyCall() returned err: %v, wantErr %v", err, test.wantErr)
   208  			}
   209  		})
   210  	}
   211  }
   212  
   213  func (s) TestUnmarshalCluster_WithUpdateValidatorFunc(t *testing.T) {
   214  	const (
   215  		serviceName                     = "my-service-client-side-xds"
   216  		missingIdentityProviderInstance = "missing-identity-provider-instance"
   217  		missingRootProviderInstance     = "missing-root-provider-instance"
   218  	)
   219  
   220  	tests := []struct {
   221  		name           string
   222  		securityConfig *v3corepb.TransportSocket
   223  		wantErr        bool
   224  	}{
   225  		{
   226  			name: "both identity and root providers are not present in bootstrap",
   227  			securityConfig: &v3corepb.TransportSocket{
   228  				Name: "envoy.transport_sockets.tls",
   229  				ConfigType: &v3corepb.TransportSocket_TypedConfig{
   230  					TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
   231  						CommonTlsContext: &v3tlspb.CommonTlsContext{
   232  							TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
   233  								InstanceName: missingIdentityProviderInstance,
   234  							},
   235  							ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
   236  								ValidationContext: &v3tlspb.CertificateValidationContext{
   237  									CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
   238  										InstanceName: missingRootProviderInstance,
   239  									},
   240  								},
   241  							},
   242  						},
   243  					}),
   244  				},
   245  			},
   246  			wantErr: true,
   247  		},
   248  		{
   249  			name: "only identity provider is not present in bootstrap",
   250  			securityConfig: &v3corepb.TransportSocket{
   251  				Name: "envoy.transport_sockets.tls",
   252  				ConfigType: &v3corepb.TransportSocket_TypedConfig{
   253  					TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
   254  						CommonTlsContext: &v3tlspb.CommonTlsContext{
   255  							TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
   256  								InstanceName: missingIdentityProviderInstance,
   257  							},
   258  							ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
   259  								ValidationContext: &v3tlspb.CertificateValidationContext{
   260  									CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
   261  										InstanceName: e2e.ClientSideCertProviderInstance,
   262  									},
   263  								},
   264  							},
   265  						},
   266  					}),
   267  				},
   268  			},
   269  			wantErr: true,
   270  		},
   271  		{
   272  			name: "only root provider is not present in bootstrap",
   273  			securityConfig: &v3corepb.TransportSocket{
   274  				Name: "envoy.transport_sockets.tls",
   275  				ConfigType: &v3corepb.TransportSocket_TypedConfig{
   276  					TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
   277  						CommonTlsContext: &v3tlspb.CommonTlsContext{
   278  							TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
   279  								InstanceName: e2e.ClientSideCertProviderInstance,
   280  							},
   281  							ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
   282  								ValidationContext: &v3tlspb.CertificateValidationContext{
   283  									CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
   284  										InstanceName: missingRootProviderInstance,
   285  									},
   286  								},
   287  							},
   288  						},
   289  					}),
   290  				},
   291  			},
   292  			wantErr: true,
   293  		},
   294  		{
   295  			name: "both identity and root providers are present in bootstrap",
   296  			securityConfig: &v3corepb.TransportSocket{
   297  				Name: "envoy.transport_sockets.tls",
   298  				ConfigType: &v3corepb.TransportSocket_TypedConfig{
   299  					TypedConfig: testutils.MarshalAny(t, &v3tlspb.UpstreamTlsContext{
   300  						CommonTlsContext: &v3tlspb.CommonTlsContext{
   301  							TlsCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
   302  								InstanceName: e2e.ClientSideCertProviderInstance,
   303  							},
   304  							ValidationContextType: &v3tlspb.CommonTlsContext_ValidationContext{
   305  								ValidationContext: &v3tlspb.CertificateValidationContext{
   306  									CaCertificateProviderInstance: &v3tlspb.CertificateProviderPluginInstance{
   307  										InstanceName: e2e.ClientSideCertProviderInstance,
   308  									},
   309  								},
   310  							},
   311  						},
   312  					}),
   313  				},
   314  			},
   315  			wantErr: false,
   316  		},
   317  	}
   318  
   319  	for _, test := range tests {
   320  		t.Run(test.name, func(t *testing.T) {
   321  			// SetupManagementServer() sets up a bootstrap file with certificate
   322  			// provider instance names: `e2e.ServerSideCertProviderInstance` and
   323  			// `e2e.ClientSideCertProviderInstance`.
   324  			managementServer, nodeID, _, resolver, cleanup1 := e2e.SetupManagementServer(t, e2e.ManagementServerOptions{})
   325  			defer cleanup1()
   326  
   327  			server := stubserver.StartTestService(t, nil)
   328  			defer server.Stop()
   329  
   330  			// This creates a `Cluster` resource with a security config which
   331  			// refers to `e2e.ClientSideCertProviderInstance` for both root and
   332  			// identity certs.
   333  			resources := e2e.DefaultClientResources(e2e.ResourceParams{
   334  				DialTarget: serviceName,
   335  				NodeID:     nodeID,
   336  				Host:       "localhost",
   337  				Port:       testutils.ParsePort(t, server.Address),
   338  				SecLevel:   e2e.SecurityLevelMTLS,
   339  			})
   340  			resources.Clusters[0].TransportSocket = test.securityConfig
   341  			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   342  			defer cancel()
   343  			if err := managementServer.Update(ctx, resources); err != nil {
   344  				t.Fatal(err)
   345  			}
   346  
   347  			cc, err := grpc.NewClient(fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolver))
   348  			if err != nil {
   349  				t.Fatalf("failed to dial local test server: %v", err)
   350  			}
   351  			defer cc.Close()
   352  
   353  			// Make a context with a shorter timeout from the top level test
   354  			// context for cases where we expect failures.
   355  			timeout := defaultTestTimeout
   356  			if test.wantErr {
   357  				timeout = defaultTestShortTimeout
   358  			}
   359  			ctx2, cancel2 := context.WithTimeout(ctx, timeout)
   360  			defer cancel2()
   361  			client := testgrpc.NewTestServiceClient(cc)
   362  			if _, err := client.EmptyCall(ctx2, &testpb.Empty{}, grpc.WaitForReady(true)); (err != nil) != test.wantErr {
   363  				t.Fatalf("EmptyCall() returned err: %v, wantErr %v", err, test.wantErr)
   364  			}
   365  		})
   366  	}
   367  }
   368  

View as plain text