google.golang.org/grpc@v1.62.1/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/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.Dial(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 }