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