gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/xds/internal/test/xds_server_integration_test.go (about)

     1  //go:build !386
     2  // +build !386
     3  
     4  /*
     5   *
     6   * Copyright 2020 gRPC authors.
     7   *
     8   * Licensed under the Apache License, Version 2.0 (the "License");
     9   * you may not use this file except in compliance with the License.
    10   * You may obtain a copy of the License at
    11   *
    12   *     http://www.apache.org/licenses/LICENSE-2.0
    13   *
    14   * Unless required by applicable law or agreed to in writing, software
    15   * distributed under the License is distributed on an "AS IS" BASIS,
    16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    17   * See the License for the specific language governing permissions and
    18   * limitations under the License.
    19   *
    20   */
    21  
    22  // Package xds_test contains e2e tests for xDS use.
    23  package xds_test
    24  
    25  import (
    26  	"context"
    27  	"fmt"
    28  	"net"
    29  	"strconv"
    30  	"strings"
    31  	"testing"
    32  
    33  	grpc "gitee.com/ks-custle/core-gm/grpc"
    34  	"gitee.com/ks-custle/core-gm/grpc/codes"
    35  	"gitee.com/ks-custle/core-gm/grpc/credentials/insecure"
    36  	"gitee.com/ks-custle/core-gm/grpc/internal/envconfig"
    37  	"gitee.com/ks-custle/core-gm/grpc/internal/testutils"
    38  	"gitee.com/ks-custle/core-gm/grpc/status"
    39  	"gitee.com/ks-custle/core-gm/grpc/xds"
    40  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/httpfilter/rbac"
    41  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/testutils/e2e"
    42  
    43  	v3corepb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/config/core/v3"
    44  	v3listenerpb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/config/listener/v3"
    45  	v3rbacpb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/config/rbac/v3"
    46  	v3routepb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/config/route/v3"
    47  	rpb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/extensions/filters/http/rbac/v3"
    48  	v3routerpb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/extensions/filters/http/router/v3"
    49  	v3httppb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
    50  	v3matcherpb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/type/matcher/v3"
    51  	xdscreds "gitee.com/ks-custle/core-gm/grpc/credentials/xds"
    52  	testpb "gitee.com/ks-custle/core-gm/grpc/test/grpc_testing"
    53  	anypb "github.com/golang/protobuf/ptypes/any"
    54  	wrapperspb "github.com/golang/protobuf/ptypes/wrappers"
    55  )
    56  
    57  const (
    58  	// Names of files inside tempdir, for certprovider plugin to watch.
    59  	certFile = "cert.pem"
    60  	keyFile  = "key.pem"
    61  	rootFile = "ca.pem"
    62  )
    63  
    64  // setupGRPCServer performs the following:
    65  //   - spin up an xDS-enabled gRPC server, configure it with xdsCredentials and
    66  //     register the test service on it
    67  //   - create a local TCP listener and start serving on it
    68  //
    69  // Returns the following:
    70  // - local listener on which the xDS-enabled gRPC server is serving on
    71  // - cleanup function to be invoked by the tests when done
    72  func setupGRPCServer(t *testing.T, bootstrapContents []byte) (net.Listener, func()) {
    73  	t.Helper()
    74  
    75  	// Configure xDS credentials to be used on the server-side.
    76  	creds, err := xdscreds.NewServerCredentials(xdscreds.ServerOptions{
    77  		FallbackCreds: insecure.NewCredentials(),
    78  	})
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  
    83  	// Initialize an xDS-enabled gRPC server and register the stubServer on it.
    84  	server := xds.NewGRPCServer(grpc.Creds(creds), xds.BootstrapContentsForTesting(bootstrapContents))
    85  	testpb.RegisterTestServiceServer(server, &testService{})
    86  
    87  	// Create a local listener and pass it to Serve().
    88  	lis, err := testutils.LocalTCPListener()
    89  	if err != nil {
    90  		t.Fatalf("testutils.LocalTCPListener() failed: %v", err)
    91  	}
    92  
    93  	go func() {
    94  		if err := server.Serve(lis); err != nil {
    95  			t.Errorf("Serve() failed: %v", err)
    96  		}
    97  	}()
    98  
    99  	return lis, func() {
   100  		server.Stop()
   101  	}
   102  }
   103  
   104  func hostPortFromListener(lis net.Listener) (string, uint32, error) {
   105  	host, p, err := net.SplitHostPort(lis.Addr().String())
   106  	if err != nil {
   107  		return "", 0, fmt.Errorf("net.SplitHostPort(%s) failed: %v", lis.Addr().String(), err)
   108  	}
   109  	port, err := strconv.ParseInt(p, 10, 32)
   110  	if err != nil {
   111  		return "", 0, fmt.Errorf("strconv.ParseInt(%s, 10, 32) failed: %v", p, err)
   112  	}
   113  	return host, uint32(port), nil
   114  }
   115  
   116  // TestServerSideXDS_Fallback is an e2e test which verifies xDS credentials
   117  // fallback functionality.
   118  //
   119  // The following sequence of events happen as part of this test:
   120  //   - An xDS-enabled gRPC server is created and xDS credentials are configured.
   121  //   - xDS is enabled on the client by the use of the xds:/// scheme, and xDS
   122  //     credentials are configured.
   123  //   - Control plane is configured to not send any security configuration to both
   124  //     the client and the server. This results in both of them using the
   125  //     configured fallback credentials (which is insecure creds in this case).
   126  func (s) TestServerSideXDS_Fallback(t *testing.T) {
   127  	managementServer, nodeID, bootstrapContents, resolver, cleanup1 := setupManagementServer(t)
   128  	defer cleanup1()
   129  
   130  	lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
   131  	defer cleanup2()
   132  
   133  	// Grab the host and port of the server and create client side xDS resources
   134  	// corresponding to it. This contains default resources with no security
   135  	// configuration in the Cluster resources.
   136  	host, port, err := hostPortFromListener(lis)
   137  	if err != nil {
   138  		t.Fatalf("failed to retrieve host and port of server: %v", err)
   139  	}
   140  	const serviceName = "my-service-fallback"
   141  	resources := e2e.DefaultClientResources(e2e.ResourceParams{
   142  		DialTarget: serviceName,
   143  		NodeID:     nodeID,
   144  		Host:       host,
   145  		Port:       port,
   146  		SecLevel:   e2e.SecurityLevelNone,
   147  	})
   148  
   149  	// Create an inbound xDS listener resource for the server side that does not
   150  	// contain any security configuration. This should force the server-side
   151  	// xdsCredentials to use fallback.
   152  	inboundLis := e2e.DefaultServerListener(host, port, e2e.SecurityLevelNone)
   153  	resources.Listeners = append(resources.Listeners, inboundLis)
   154  
   155  	// Setup the management server with client and server-side resources.
   156  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   157  	defer cancel()
   158  	if err := managementServer.Update(ctx, resources); err != nil {
   159  		t.Fatal(err)
   160  	}
   161  
   162  	// Create client-side xDS credentials with an insecure fallback.
   163  	creds, err := xdscreds.NewClientCredentials(xdscreds.ClientOptions{
   164  		FallbackCreds: insecure.NewCredentials(),
   165  	})
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  
   170  	// Create a ClientConn with the xds scheme and make a successful RPC.
   171  	cc, err := grpc.DialContext(ctx, fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(creds), grpc.WithResolvers(resolver))
   172  	if err != nil {
   173  		t.Fatalf("failed to dial local test server: %v", err)
   174  	}
   175  	defer cc.Close()
   176  
   177  	client := testpb.NewTestServiceClient(cc)
   178  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
   179  		t.Errorf("rpc EmptyCall() failed: %v", err)
   180  	}
   181  }
   182  
   183  // TestServerSideXDS_FileWatcherCerts is an e2e test which verifies xDS
   184  // credentials with file watcher certificate provider.
   185  //
   186  // The following sequence of events happen as part of this test:
   187  //   - An xDS-enabled gRPC server is created and xDS credentials are configured.
   188  //   - xDS is enabled on the client by the use of the xds:/// scheme, and xDS
   189  //     credentials are configured.
   190  //   - Control plane is configured to send security configuration to both the
   191  //     client and the server, pointing to the file watcher certificate provider.
   192  //     We verify both TLS and mTLS scenarios.
   193  func (s) TestServerSideXDS_FileWatcherCerts(t *testing.T) {
   194  	tests := []struct {
   195  		name     string
   196  		secLevel e2e.SecurityLevel
   197  	}{
   198  		{
   199  			name:     "tls",
   200  			secLevel: e2e.SecurityLevelTLS,
   201  		},
   202  		{
   203  			name:     "mtls",
   204  			secLevel: e2e.SecurityLevelMTLS,
   205  		},
   206  	}
   207  	for _, test := range tests {
   208  		t.Run(test.name, func(t *testing.T) {
   209  			managementServer, nodeID, bootstrapContents, resolver, cleanup1 := setupManagementServer(t)
   210  			defer cleanup1()
   211  
   212  			lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
   213  			defer cleanup2()
   214  
   215  			// Grab the host and port of the server and create client side xDS
   216  			// resources corresponding to it.
   217  			host, port, err := hostPortFromListener(lis)
   218  			if err != nil {
   219  				t.Fatalf("failed to retrieve host and port of server: %v", err)
   220  			}
   221  
   222  			// Create xDS resources to be consumed on the client side. This
   223  			// includes the listener, route configuration, cluster (with
   224  			// security configuration) and endpoint resources.
   225  			serviceName := "my-service-file-watcher-certs-" + test.name
   226  			resources := e2e.DefaultClientResources(e2e.ResourceParams{
   227  				DialTarget: serviceName,
   228  				NodeID:     nodeID,
   229  				Host:       host,
   230  				Port:       port,
   231  				SecLevel:   test.secLevel,
   232  			})
   233  
   234  			// Create an inbound xDS listener resource for the server side that
   235  			// contains security configuration pointing to the file watcher
   236  			// plugin.
   237  			inboundLis := e2e.DefaultServerListener(host, port, test.secLevel)
   238  			resources.Listeners = append(resources.Listeners, inboundLis)
   239  
   240  			// Setup the management server with client and server resources.
   241  			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   242  			defer cancel()
   243  			if err := managementServer.Update(ctx, resources); err != nil {
   244  				t.Fatal(err)
   245  			}
   246  
   247  			// Create client-side xDS credentials with an insecure fallback.
   248  			creds, err := xdscreds.NewClientCredentials(xdscreds.ClientOptions{
   249  				FallbackCreds: insecure.NewCredentials(),
   250  			})
   251  			if err != nil {
   252  				t.Fatal(err)
   253  			}
   254  
   255  			// Create a ClientConn with the xds scheme and make an RPC.
   256  			cc, err := grpc.DialContext(ctx, fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(creds), grpc.WithResolvers(resolver))
   257  			if err != nil {
   258  				t.Fatalf("failed to dial local test server: %v", err)
   259  			}
   260  			defer cc.Close()
   261  
   262  			client := testpb.NewTestServiceClient(cc)
   263  			if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
   264  				t.Fatalf("rpc EmptyCall() failed: %v", err)
   265  			}
   266  		})
   267  	}
   268  }
   269  
   270  // TestServerSideXDS_SecurityConfigChange is an e2e test where xDS is enabled on
   271  // the server-side and xdsCredentials are configured for security. The control
   272  // plane initially does not any security configuration. This forces the
   273  // xdsCredentials to use fallback creds, which is this case is insecure creds.
   274  // We verify that a client connecting with TLS creds is not able to successfully
   275  // make an RPC. The control plane then sends a listener resource with security
   276  // configuration pointing to the use of the file_watcher plugin and we verify
   277  // that the same client is now able to successfully make an RPC.
   278  func (s) TestServerSideXDS_SecurityConfigChange(t *testing.T) {
   279  	managementServer, nodeID, bootstrapContents, resolver, cleanup1 := setupManagementServer(t)
   280  	defer cleanup1()
   281  
   282  	lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
   283  	defer cleanup2()
   284  
   285  	// Grab the host and port of the server and create client side xDS resources
   286  	// corresponding to it. This contains default resources with no security
   287  	// configuration in the Cluster resource. This should force the xDS
   288  	// credentials on the client to use its fallback.
   289  	host, port, err := hostPortFromListener(lis)
   290  	if err != nil {
   291  		t.Fatalf("failed to retrieve host and port of server: %v", err)
   292  	}
   293  	const serviceName = "my-service-security-config-change"
   294  	resources := e2e.DefaultClientResources(e2e.ResourceParams{
   295  		DialTarget: serviceName,
   296  		NodeID:     nodeID,
   297  		Host:       host,
   298  		Port:       port,
   299  		SecLevel:   e2e.SecurityLevelNone,
   300  	})
   301  
   302  	// Create an inbound xDS listener resource for the server side that does not
   303  	// contain any security configuration. This should force the xDS credentials
   304  	// on server to use its fallback.
   305  	inboundLis := e2e.DefaultServerListener(host, port, e2e.SecurityLevelNone)
   306  	resources.Listeners = append(resources.Listeners, inboundLis)
   307  
   308  	// Setup the management server with client and server-side resources.
   309  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   310  	defer cancel()
   311  	if err := managementServer.Update(ctx, resources); err != nil {
   312  		t.Fatal(err)
   313  	}
   314  
   315  	// Create client-side xDS credentials with an insecure fallback.
   316  	xdsCreds, err := xdscreds.NewClientCredentials(xdscreds.ClientOptions{
   317  		FallbackCreds: insecure.NewCredentials(),
   318  	})
   319  	if err != nil {
   320  		t.Fatal(err)
   321  	}
   322  
   323  	// Create a ClientConn with the xds scheme and make a successful RPC.
   324  	xdsCC, err := grpc.DialContext(ctx, fmt.Sprintf("xds:///%s", serviceName), grpc.WithTransportCredentials(xdsCreds), grpc.WithResolvers(resolver))
   325  	if err != nil {
   326  		t.Fatalf("failed to dial local test server: %v", err)
   327  	}
   328  	defer xdsCC.Close()
   329  
   330  	client := testpb.NewTestServiceClient(xdsCC)
   331  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
   332  		t.Fatalf("rpc EmptyCall() failed: %v", err)
   333  	}
   334  
   335  	// Create a ClientConn with TLS creds. This should fail since the server is
   336  	// using fallback credentials which in this case in insecure creds.
   337  	tlsCreds := createClientTLSCredentials(t)
   338  	tlsCC, err := grpc.DialContext(ctx, lis.Addr().String(), grpc.WithTransportCredentials(tlsCreds))
   339  	if err != nil {
   340  		t.Fatalf("failed to dial local test server: %v", err)
   341  	}
   342  	defer tlsCC.Close()
   343  
   344  	// We don't set 'waitForReady` here since we want this call to failfast.
   345  	client = testpb.NewTestServiceClient(tlsCC)
   346  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}); status.Code(err) != codes.Unavailable {
   347  		t.Fatal("rpc EmptyCall() succeeded when expected to fail")
   348  	}
   349  
   350  	// Switch server and client side resources with ones that contain required
   351  	// security configuration for mTLS with a file watcher certificate provider.
   352  	resources = e2e.DefaultClientResources(e2e.ResourceParams{
   353  		DialTarget: serviceName,
   354  		NodeID:     nodeID,
   355  		Host:       host,
   356  		Port:       port,
   357  		SecLevel:   e2e.SecurityLevelMTLS,
   358  	})
   359  	inboundLis = e2e.DefaultServerListener(host, port, e2e.SecurityLevelMTLS)
   360  	resources.Listeners = append(resources.Listeners, inboundLis)
   361  	if err := managementServer.Update(ctx, resources); err != nil {
   362  		t.Fatal(err)
   363  	}
   364  
   365  	// Make another RPC with `waitForReady` set and expect this to succeed.
   366  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
   367  		t.Fatalf("rpc EmptyCall() failed: %v", err)
   368  	}
   369  }
   370  
   371  // TestServerSideXDS_RouteConfiguration is an e2e test which verifies routing
   372  // functionality. The xDS enabled server will be set up with route configuration
   373  // where the route configuration has routes with the correct routing actions
   374  // (NonForwardingAction), and the RPC's matching those routes should proceed as
   375  // normal.
   376  func (s) TestServerSideXDS_RouteConfiguration(t *testing.T) {
   377  	oldRBAC := envconfig.XDSRBAC
   378  	envconfig.XDSRBAC = true
   379  	defer func() {
   380  		envconfig.XDSRBAC = oldRBAC
   381  	}()
   382  	managementServer, nodeID, bootstrapContents, resolver, cleanup1 := setupManagementServer(t)
   383  	defer cleanup1()
   384  
   385  	lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
   386  	defer cleanup2()
   387  
   388  	host, port, err := hostPortFromListener(lis)
   389  	if err != nil {
   390  		t.Fatalf("failed to retrieve host and port of server: %v", err)
   391  	}
   392  	const serviceName = "my-service-fallback"
   393  	resources := e2e.DefaultClientResources(e2e.ResourceParams{
   394  		DialTarget: serviceName,
   395  		NodeID:     nodeID,
   396  		Host:       host,
   397  		Port:       port,
   398  		SecLevel:   e2e.SecurityLevelNone,
   399  	})
   400  
   401  	// Create an inbound xDS listener resource with route configuration which
   402  	// selectively will allow RPC's through or not. This will test routing in
   403  	// xds(Unary|Stream)Interceptors.
   404  	vhs := []*v3routepb.VirtualHost{
   405  		// Virtual host that will never be matched to test Virtual Host selection.
   406  		{
   407  			Domains: []string{"this will not match*"},
   408  			Routes: []*v3routepb.Route{
   409  				{
   410  					Match: &v3routepb.RouteMatch{
   411  						PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"},
   412  					},
   413  					Action: &v3routepb.Route_NonForwardingAction{},
   414  				},
   415  			},
   416  		},
   417  		// This Virtual Host will actually get matched to.
   418  		{
   419  			Domains: []string{"*"},
   420  			Routes: []*v3routepb.Route{
   421  				// A routing rule that can be selectively triggered based on properties about incoming RPC.
   422  				{
   423  					Match: &v3routepb.RouteMatch{
   424  						PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/grpc.testing.TestService/EmptyCall"},
   425  						// "Fully-qualified RPC method name with leading slash. Same as :path header".
   426  					},
   427  					// Correct Action, so RPC's that match this route should proceed to interceptor processing.
   428  					Action: &v3routepb.Route_NonForwardingAction{},
   429  				},
   430  				// This routing rule is matched the same way as the one above,
   431  				// except has an incorrect action for the server side. However,
   432  				// since routing chooses the first route which matches an
   433  				// incoming RPC, this should never get invoked (iteration
   434  				// through this route slice is deterministic).
   435  				{
   436  					Match: &v3routepb.RouteMatch{
   437  						PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/grpc.testing.TestService/EmptyCall"},
   438  						// "Fully-qualified RPC method name with leading slash. Same as :path header".
   439  					},
   440  					// Incorrect Action, so RPC's that match this route should get denied.
   441  					Action: &v3routepb.Route_Route{
   442  						Route: &v3routepb.RouteAction{ClusterSpecifier: &v3routepb.RouteAction_Cluster{Cluster: ""}},
   443  					},
   444  				},
   445  				// Another routing rule that can be selectively triggered based on incoming RPC.
   446  				{
   447  					Match: &v3routepb.RouteMatch{
   448  						PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/grpc.testing.TestService/UnaryCall"},
   449  					},
   450  					// Wrong action (!Non_Forwarding_Action) so RPC's that match this route should get denied.
   451  					Action: &v3routepb.Route_Route{
   452  						Route: &v3routepb.RouteAction{ClusterSpecifier: &v3routepb.RouteAction_Cluster{Cluster: ""}},
   453  					},
   454  				},
   455  				// Another routing rule that can be selectively triggered based on incoming RPC.
   456  				{
   457  					Match: &v3routepb.RouteMatch{
   458  						PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/grpc.testing.TestService/StreamingInputCall"},
   459  					},
   460  					// Wrong action (!Non_Forwarding_Action) so RPC's that match this route should get denied.
   461  					Action: &v3routepb.Route_Route{
   462  						Route: &v3routepb.RouteAction{ClusterSpecifier: &v3routepb.RouteAction_Cluster{Cluster: ""}},
   463  					},
   464  				},
   465  				// Not matching route, this is be able to get invoked logically (i.e. doesn't have to match the Route configurations above).
   466  			}},
   467  	}
   468  	inboundLis := &v3listenerpb.Listener{
   469  		Name: fmt.Sprintf(e2e.ServerListenerResourceNameTemplate, net.JoinHostPort(host, strconv.Itoa(int(port)))),
   470  		Address: &v3corepb.Address{
   471  			Address: &v3corepb.Address_SocketAddress{
   472  				SocketAddress: &v3corepb.SocketAddress{
   473  					Address: host,
   474  					PortSpecifier: &v3corepb.SocketAddress_PortValue{
   475  						PortValue: port,
   476  					},
   477  				},
   478  			},
   479  		},
   480  		FilterChains: []*v3listenerpb.FilterChain{
   481  			{
   482  				Name: "v4-wildcard",
   483  				FilterChainMatch: &v3listenerpb.FilterChainMatch{
   484  					PrefixRanges: []*v3corepb.CidrRange{
   485  						{
   486  							AddressPrefix: "0.0.0.0",
   487  							PrefixLen: &wrapperspb.UInt32Value{
   488  								Value: uint32(0),
   489  							},
   490  						},
   491  					},
   492  					SourceType: v3listenerpb.FilterChainMatch_SAME_IP_OR_LOOPBACK,
   493  					SourcePrefixRanges: []*v3corepb.CidrRange{
   494  						{
   495  							AddressPrefix: "0.0.0.0",
   496  							PrefixLen: &wrapperspb.UInt32Value{
   497  								Value: uint32(0),
   498  							},
   499  						},
   500  					},
   501  				},
   502  				Filters: []*v3listenerpb.Filter{
   503  					{
   504  						Name: "filter-1",
   505  						ConfigType: &v3listenerpb.Filter_TypedConfig{
   506  							TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
   507  								HttpFilters: []*v3httppb.HttpFilter{e2e.HTTPFilter("router", &v3routerpb.Router{})},
   508  								RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
   509  									RouteConfig: &v3routepb.RouteConfiguration{
   510  										Name:         "routeName",
   511  										VirtualHosts: vhs,
   512  									},
   513  								},
   514  							}),
   515  						},
   516  					},
   517  				},
   518  			},
   519  			{
   520  				Name: "v6-wildcard",
   521  				FilterChainMatch: &v3listenerpb.FilterChainMatch{
   522  					PrefixRanges: []*v3corepb.CidrRange{
   523  						{
   524  							AddressPrefix: "::",
   525  							PrefixLen: &wrapperspb.UInt32Value{
   526  								Value: uint32(0),
   527  							},
   528  						},
   529  					},
   530  					SourceType: v3listenerpb.FilterChainMatch_SAME_IP_OR_LOOPBACK,
   531  					SourcePrefixRanges: []*v3corepb.CidrRange{
   532  						{
   533  							AddressPrefix: "::",
   534  							PrefixLen: &wrapperspb.UInt32Value{
   535  								Value: uint32(0),
   536  							},
   537  						},
   538  					},
   539  				},
   540  				Filters: []*v3listenerpb.Filter{
   541  					{
   542  						Name: "filter-1",
   543  						ConfigType: &v3listenerpb.Filter_TypedConfig{
   544  							TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
   545  								HttpFilters: []*v3httppb.HttpFilter{e2e.HTTPFilter("router", &v3routerpb.Router{})},
   546  								RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
   547  									RouteConfig: &v3routepb.RouteConfiguration{
   548  										Name:         "routeName",
   549  										VirtualHosts: vhs,
   550  									},
   551  								},
   552  							}),
   553  						},
   554  					},
   555  				},
   556  			},
   557  		},
   558  	}
   559  	resources.Listeners = append(resources.Listeners, inboundLis)
   560  
   561  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   562  	defer cancel()
   563  	// Setup the management server with client and server-side resources.
   564  	if err := managementServer.Update(ctx, resources); err != nil {
   565  		t.Fatal(err)
   566  	}
   567  
   568  	cc, err := grpc.DialContext(ctx, fmt.Sprintf("xds:///%s", serviceName), grpc.WithInsecure(), grpc.WithResolvers(resolver))
   569  	if err != nil {
   570  		t.Fatalf("failed to dial local test server: %v", err)
   571  	}
   572  	defer cc.Close()
   573  
   574  	client := testpb.NewTestServiceClient(cc)
   575  
   576  	// This Empty Call should match to a route with a correct action
   577  	// (NonForwardingAction). Thus, this RPC should proceed as normal. There is
   578  	// a routing rule that this RPC would match to that has an incorrect action,
   579  	// but the server should only use the first route matched to with the
   580  	// correct action.
   581  	if _, err = client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil {
   582  		t.Fatalf("rpc EmptyCall() failed: %v", err)
   583  	}
   584  
   585  	// This Unary Call should match to a route with an incorrect action. Thus,
   586  	// this RPC should not go through as per A36, and this call should receive
   587  	// an error with codes.Unavailable.
   588  	if _, err = client.UnaryCall(ctx, &testpb.SimpleRequest{}); status.Code(err) != codes.Unavailable {
   589  		t.Fatalf("client.UnaryCall() = _, %v, want _, error code %s", err, codes.Unavailable)
   590  	}
   591  
   592  	// This Streaming Call should match to a route with an incorrect action.
   593  	// Thus, this RPC should not go through as per A36, and this call should
   594  	// receive an error with codes.Unavailable.
   595  	stream, err := client.StreamingInputCall(ctx)
   596  	if err != nil {
   597  		t.Fatalf("StreamingInputCall(_) = _, %v, want <nil>", err)
   598  	}
   599  	if _, err = stream.CloseAndRecv(); status.Code(err) != codes.Unavailable || !strings.Contains(err.Error(), "the incoming RPC matched to a route that was not of action type non forwarding") {
   600  		t.Fatalf("streaming RPC should have been denied")
   601  	}
   602  
   603  	// This Full Duplex should not match to a route, and thus should return an
   604  	// error and not proceed.
   605  	dStream, err := client.FullDuplexCall(ctx)
   606  	if err != nil {
   607  		t.Fatalf("FullDuplexCall(_) = _, %v, want <nil>", err)
   608  	}
   609  	if _, err = dStream.Recv(); status.Code(err) != codes.Unavailable || !strings.Contains(err.Error(), "the incoming RPC did not match a configured Route") {
   610  		t.Fatalf("streaming RPC should have been denied")
   611  	}
   612  }
   613  
   614  // serverListenerWithRBACHTTPFilters returns an xds Listener resource with HTTP Filters defined in the HCM, and a route
   615  // configuration that always matches to a route and a VH.
   616  func serverListenerWithRBACHTTPFilters(host string, port uint32, rbacCfg *rpb.RBAC) *v3listenerpb.Listener {
   617  	// Rather than declare typed config inline, take a HCM proto and append the
   618  	// RBAC Filters to it.
   619  	hcm := &v3httppb.HttpConnectionManager{
   620  		RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
   621  			RouteConfig: &v3routepb.RouteConfiguration{
   622  				Name: "routeName",
   623  				VirtualHosts: []*v3routepb.VirtualHost{{
   624  					Domains: []string{"*"},
   625  					Routes: []*v3routepb.Route{{
   626  						Match: &v3routepb.RouteMatch{
   627  							PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"},
   628  						},
   629  						Action: &v3routepb.Route_NonForwardingAction{},
   630  					}},
   631  					// This tests override parsing + building when RBAC Filter
   632  					// passed both normal and override config.
   633  					TypedPerFilterConfig: map[string]*anypb.Any{
   634  						"rbac": testutils.MarshalAny(&rpb.RBACPerRoute{Rbac: rbacCfg}),
   635  					},
   636  				}}},
   637  		},
   638  	}
   639  	hcm.HttpFilters = nil
   640  	hcm.HttpFilters = append(hcm.HttpFilters, e2e.HTTPFilter("rbac", rbacCfg))
   641  	hcm.HttpFilters = append(hcm.HttpFilters, e2e.RouterHTTPFilter)
   642  
   643  	return &v3listenerpb.Listener{
   644  		Name: fmt.Sprintf(e2e.ServerListenerResourceNameTemplate, net.JoinHostPort(host, strconv.Itoa(int(port)))),
   645  		Address: &v3corepb.Address{
   646  			Address: &v3corepb.Address_SocketAddress{
   647  				SocketAddress: &v3corepb.SocketAddress{
   648  					Address: host,
   649  					PortSpecifier: &v3corepb.SocketAddress_PortValue{
   650  						PortValue: port,
   651  					},
   652  				},
   653  			},
   654  		},
   655  		FilterChains: []*v3listenerpb.FilterChain{
   656  			{
   657  				Name: "v4-wildcard",
   658  				FilterChainMatch: &v3listenerpb.FilterChainMatch{
   659  					PrefixRanges: []*v3corepb.CidrRange{
   660  						{
   661  							AddressPrefix: "0.0.0.0",
   662  							PrefixLen: &wrapperspb.UInt32Value{
   663  								Value: uint32(0),
   664  							},
   665  						},
   666  					},
   667  					SourceType: v3listenerpb.FilterChainMatch_SAME_IP_OR_LOOPBACK,
   668  					SourcePrefixRanges: []*v3corepb.CidrRange{
   669  						{
   670  							AddressPrefix: "0.0.0.0",
   671  							PrefixLen: &wrapperspb.UInt32Value{
   672  								Value: uint32(0),
   673  							},
   674  						},
   675  					},
   676  				},
   677  				Filters: []*v3listenerpb.Filter{
   678  					{
   679  						Name: "filter-1",
   680  						ConfigType: &v3listenerpb.Filter_TypedConfig{
   681  							TypedConfig: testutils.MarshalAny(hcm),
   682  						},
   683  					},
   684  				},
   685  			},
   686  			{
   687  				Name: "v6-wildcard",
   688  				FilterChainMatch: &v3listenerpb.FilterChainMatch{
   689  					PrefixRanges: []*v3corepb.CidrRange{
   690  						{
   691  							AddressPrefix: "::",
   692  							PrefixLen: &wrapperspb.UInt32Value{
   693  								Value: uint32(0),
   694  							},
   695  						},
   696  					},
   697  					SourceType: v3listenerpb.FilterChainMatch_SAME_IP_OR_LOOPBACK,
   698  					SourcePrefixRanges: []*v3corepb.CidrRange{
   699  						{
   700  							AddressPrefix: "::",
   701  							PrefixLen: &wrapperspb.UInt32Value{
   702  								Value: uint32(0),
   703  							},
   704  						},
   705  					},
   706  				},
   707  				Filters: []*v3listenerpb.Filter{
   708  					{
   709  						Name: "filter-1",
   710  						ConfigType: &v3listenerpb.Filter_TypedConfig{
   711  							TypedConfig: testutils.MarshalAny(hcm),
   712  						},
   713  					},
   714  				},
   715  			},
   716  		},
   717  	}
   718  }
   719  
   720  // TestRBACHTTPFilter tests the xds configured RBAC HTTP Filter. It sets up the
   721  // full end to end flow, and makes sure certain RPC's are successful and proceed
   722  // as normal and certain RPC's are denied by the RBAC HTTP Filter which gets
   723  // called by hooked xds interceptors.
   724  func (s) TestRBACHTTPFilter(t *testing.T) {
   725  	oldRBAC := envconfig.XDSRBAC
   726  	envconfig.XDSRBAC = true
   727  	defer func() {
   728  		envconfig.XDSRBAC = oldRBAC
   729  	}()
   730  	rbac.RegisterForTesting()
   731  	defer rbac.UnregisterForTesting()
   732  	tests := []struct {
   733  		name                string
   734  		rbacCfg             *rpb.RBAC
   735  		wantStatusEmptyCall codes.Code
   736  		wantStatusUnaryCall codes.Code
   737  	}{
   738  		// This test tests an RBAC HTTP Filter which is configured to allow any RPC.
   739  		// Any RPC passing through this RBAC HTTP Filter should proceed as normal.
   740  		{
   741  			name: "allow-anything",
   742  			rbacCfg: &rpb.RBAC{
   743  				Rules: &v3rbacpb.RBAC{
   744  					Action: v3rbacpb.RBAC_ALLOW,
   745  					Policies: map[string]*v3rbacpb.Policy{
   746  						"anyone": {
   747  							Permissions: []*v3rbacpb.Permission{
   748  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   749  							},
   750  							Principals: []*v3rbacpb.Principal{
   751  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   752  							},
   753  						},
   754  					},
   755  				},
   756  			},
   757  			wantStatusEmptyCall: codes.OK,
   758  			wantStatusUnaryCall: codes.OK,
   759  		},
   760  		// This test tests an RBAC HTTP Filter which is configured to allow only
   761  		// RPC's with certain paths ("UnaryCall"). Only unary calls passing
   762  		// through this RBAC HTTP Filter should proceed as normal, and any
   763  		// others should be denied.
   764  		{
   765  			name: "allow-certain-path",
   766  			rbacCfg: &rpb.RBAC{
   767  				Rules: &v3rbacpb.RBAC{
   768  					Action: v3rbacpb.RBAC_ALLOW,
   769  					Policies: map[string]*v3rbacpb.Policy{
   770  						"certain-path": {
   771  							Permissions: []*v3rbacpb.Permission{
   772  								{Rule: &v3rbacpb.Permission_UrlPath{UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "/grpc.testing.TestService/UnaryCall"}}}}}},
   773  							},
   774  							Principals: []*v3rbacpb.Principal{
   775  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   776  							},
   777  						},
   778  					},
   779  				},
   780  			},
   781  			wantStatusEmptyCall: codes.PermissionDenied,
   782  			wantStatusUnaryCall: codes.OK,
   783  		},
   784  		// This test that a RBAC Config with nil rules means that every RPC is
   785  		// allowed. This maps to the line "If absent, no enforcing RBAC policy
   786  		// will be applied" from the RBAC Proto documentation for the Rules
   787  		// field.
   788  		{
   789  			name: "absent-rules",
   790  			rbacCfg: &rpb.RBAC{
   791  				Rules: nil,
   792  			},
   793  			wantStatusEmptyCall: codes.OK,
   794  			wantStatusUnaryCall: codes.OK,
   795  		},
   796  		// The two tests below test that configuring the xDS RBAC HTTP Filter
   797  		// with :authority and host header matchers end up being logically
   798  		// equivalent. This represents functionality from this line in A41 -
   799  		// "As documented for HeaderMatcher, Envoy aliases :authority and Host
   800  		// in its header map implementation, so they should be treated
   801  		// equivalent for the RBAC matchers; there must be no behavior change
   802  		// depending on which of the two header names is used in the RBAC
   803  		// policy."
   804  
   805  		// This test tests an xDS RBAC Filter with an :authority header matcher.
   806  		{
   807  			name: "match-on-authority",
   808  			rbacCfg: &rpb.RBAC{
   809  				Rules: &v3rbacpb.RBAC{
   810  					Action: v3rbacpb.RBAC_ALLOW,
   811  					Policies: map[string]*v3rbacpb.Policy{
   812  						"match-on-authority": {
   813  							Permissions: []*v3rbacpb.Permission{
   814  								{Rule: &v3rbacpb.Permission_Header{Header: &v3routepb.HeaderMatcher{Name: ":authority", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_PrefixMatch{PrefixMatch: "my-service-fallback"}}}},
   815  							},
   816  							Principals: []*v3rbacpb.Principal{
   817  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   818  							},
   819  						},
   820  					},
   821  				},
   822  			},
   823  			wantStatusEmptyCall: codes.OK,
   824  			wantStatusUnaryCall: codes.OK,
   825  		},
   826  		// This test tests that configuring an xDS RBAC Filter with a host
   827  		// header matcher has the same behavior as if it was configured with
   828  		// :authority. Since host and authority are aliased, this should still
   829  		// continue to match on incoming RPC's :authority, just as the test
   830  		// above.
   831  		{
   832  			name: "match-on-host",
   833  			rbacCfg: &rpb.RBAC{
   834  				Rules: &v3rbacpb.RBAC{
   835  					Action: v3rbacpb.RBAC_ALLOW,
   836  					Policies: map[string]*v3rbacpb.Policy{
   837  						"match-on-authority": {
   838  							Permissions: []*v3rbacpb.Permission{
   839  								{Rule: &v3rbacpb.Permission_Header{Header: &v3routepb.HeaderMatcher{Name: "host", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_PrefixMatch{PrefixMatch: "my-service-fallback"}}}},
   840  							},
   841  							Principals: []*v3rbacpb.Principal{
   842  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   843  							},
   844  						},
   845  					},
   846  				},
   847  			},
   848  			wantStatusEmptyCall: codes.OK,
   849  			wantStatusUnaryCall: codes.OK,
   850  		},
   851  		// This test tests that the RBAC HTTP Filter hard codes the :method
   852  		// header to POST. Since the RBAC Configuration says to deny every RPC
   853  		// with a method :POST, every RPC tried should be denied.
   854  		{
   855  			name: "deny-post",
   856  			rbacCfg: &rpb.RBAC{
   857  				Rules: &v3rbacpb.RBAC{
   858  					Action: v3rbacpb.RBAC_DENY,
   859  					Policies: map[string]*v3rbacpb.Policy{
   860  						"post-method": {
   861  							Permissions: []*v3rbacpb.Permission{
   862  								{Rule: &v3rbacpb.Permission_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_ExactMatch{ExactMatch: "POST"}}}},
   863  							},
   864  							Principals: []*v3rbacpb.Principal{
   865  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   866  							},
   867  						},
   868  					},
   869  				},
   870  			},
   871  			wantStatusEmptyCall: codes.PermissionDenied,
   872  			wantStatusUnaryCall: codes.PermissionDenied,
   873  		},
   874  		// This test tests that RBAC ignores the TE: trailers header (which is
   875  		// hardcoded in http2_client.go for every RPC). Since the RBAC
   876  		// Configuration says to only ALLOW RPC's with a TE: Trailers, every RPC
   877  		// tried should be denied.
   878  		{
   879  			name: "allow-only-te",
   880  			rbacCfg: &rpb.RBAC{
   881  				Rules: &v3rbacpb.RBAC{
   882  					Action: v3rbacpb.RBAC_ALLOW,
   883  					Policies: map[string]*v3rbacpb.Policy{
   884  						"post-method": {
   885  							Permissions: []*v3rbacpb.Permission{
   886  								{Rule: &v3rbacpb.Permission_Header{Header: &v3routepb.HeaderMatcher{Name: "TE", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_ExactMatch{ExactMatch: "trailers"}}}},
   887  							},
   888  							Principals: []*v3rbacpb.Principal{
   889  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   890  							},
   891  						},
   892  					},
   893  				},
   894  			},
   895  			wantStatusEmptyCall: codes.PermissionDenied,
   896  			wantStatusUnaryCall: codes.PermissionDenied,
   897  		},
   898  		// This test tests that an RBAC Config with Action.LOG configured allows
   899  		// every RPC through. This maps to the line "At this time, if the
   900  		// RBAC.action is Action.LOG then the policy will be completely ignored,
   901  		// as if RBAC was not configurated." from A41
   902  		{
   903  			name: "action-log",
   904  			rbacCfg: &rpb.RBAC{
   905  				Rules: &v3rbacpb.RBAC{
   906  					Action: v3rbacpb.RBAC_LOG,
   907  					Policies: map[string]*v3rbacpb.Policy{
   908  						"anyone": {
   909  							Permissions: []*v3rbacpb.Permission{
   910  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   911  							},
   912  							Principals: []*v3rbacpb.Principal{
   913  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   914  							},
   915  						},
   916  					},
   917  				},
   918  			},
   919  			wantStatusEmptyCall: codes.OK,
   920  			wantStatusUnaryCall: codes.OK,
   921  		},
   922  	}
   923  
   924  	for _, test := range tests {
   925  		t.Run(test.name, func(t *testing.T) {
   926  			func() {
   927  				managementServer, nodeID, bootstrapContents, resolver, cleanup1 := setupManagementServer(t)
   928  				defer cleanup1()
   929  
   930  				lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
   931  				defer cleanup2()
   932  
   933  				host, port, err := hostPortFromListener(lis)
   934  				if err != nil {
   935  					t.Fatalf("failed to retrieve host and port of server: %v", err)
   936  				}
   937  				const serviceName = "my-service-fallback"
   938  				resources := e2e.DefaultClientResources(e2e.ResourceParams{
   939  					DialTarget: serviceName,
   940  					NodeID:     nodeID,
   941  					Host:       host,
   942  					Port:       port,
   943  					SecLevel:   e2e.SecurityLevelNone,
   944  				})
   945  				inboundLis := serverListenerWithRBACHTTPFilters(host, port, test.rbacCfg)
   946  				resources.Listeners = append(resources.Listeners, inboundLis)
   947  
   948  				ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   949  				defer cancel()
   950  				// Setup the management server with client and server-side resources.
   951  				if err := managementServer.Update(ctx, resources); err != nil {
   952  					t.Fatal(err)
   953  				}
   954  
   955  				cc, err := grpc.DialContext(ctx, fmt.Sprintf("xds:///%s", serviceName), grpc.WithInsecure(), grpc.WithResolvers(resolver))
   956  				if err != nil {
   957  					t.Fatalf("failed to dial local test server: %v", err)
   958  				}
   959  				defer cc.Close()
   960  
   961  				client := testpb.NewTestServiceClient(cc)
   962  
   963  				if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); status.Code(err) != test.wantStatusEmptyCall {
   964  					t.Fatalf("EmptyCall() returned err with status: %v, wantStatusEmptyCall: %v", status.Code(err), test.wantStatusEmptyCall)
   965  				}
   966  
   967  				if _, err := client.UnaryCall(ctx, &testpb.SimpleRequest{}); status.Code(err) != test.wantStatusUnaryCall {
   968  					t.Fatalf("UnaryCall() returned err with status: %v, wantStatusUnaryCall: %v", err, test.wantStatusUnaryCall)
   969  				}
   970  
   971  				// Toggle the RBAC Env variable off, this should disable RBAC and allow any RPC"s through (will not go through
   972  				// routing or processed by HTTP Filters and thus will never get denied by RBAC).
   973  				envconfig.XDSRBAC = false
   974  				if _, err := client.EmptyCall(ctx, &testpb.Empty{}); status.Code(err) != codes.OK {
   975  					t.Fatalf("EmptyCall() returned err with status: %v, once RBAC is disabled all RPC's should proceed as normal", status.Code(err))
   976  				}
   977  				if _, err := client.UnaryCall(ctx, &testpb.SimpleRequest{}); status.Code(err) != codes.OK {
   978  					t.Fatalf("UnaryCall() returned err with status: %v, once RBAC is disabled all RPC's should proceed as normal", status.Code(err))
   979  				}
   980  				// Toggle RBAC back on for next iterations.
   981  				envconfig.XDSRBAC = true
   982  			}()
   983  		})
   984  	}
   985  }
   986  
   987  // serverListenerWithBadRouteConfiguration returns an xds Listener resource with
   988  // a Route Configuration that will never successfully match in order to test
   989  // RBAC Environment variable being toggled on and off.
   990  func serverListenerWithBadRouteConfiguration(host string, port uint32) *v3listenerpb.Listener {
   991  	return &v3listenerpb.Listener{
   992  		Name: fmt.Sprintf(e2e.ServerListenerResourceNameTemplate, net.JoinHostPort(host, strconv.Itoa(int(port)))),
   993  		Address: &v3corepb.Address{
   994  			Address: &v3corepb.Address_SocketAddress{
   995  				SocketAddress: &v3corepb.SocketAddress{
   996  					Address: host,
   997  					PortSpecifier: &v3corepb.SocketAddress_PortValue{
   998  						PortValue: port,
   999  					},
  1000  				},
  1001  			},
  1002  		},
  1003  		FilterChains: []*v3listenerpb.FilterChain{
  1004  			{
  1005  				Name: "v4-wildcard",
  1006  				FilterChainMatch: &v3listenerpb.FilterChainMatch{
  1007  					PrefixRanges: []*v3corepb.CidrRange{
  1008  						{
  1009  							AddressPrefix: "0.0.0.0",
  1010  							PrefixLen: &wrapperspb.UInt32Value{
  1011  								Value: uint32(0),
  1012  							},
  1013  						},
  1014  					},
  1015  					SourceType: v3listenerpb.FilterChainMatch_SAME_IP_OR_LOOPBACK,
  1016  					SourcePrefixRanges: []*v3corepb.CidrRange{
  1017  						{
  1018  							AddressPrefix: "0.0.0.0",
  1019  							PrefixLen: &wrapperspb.UInt32Value{
  1020  								Value: uint32(0),
  1021  							},
  1022  						},
  1023  					},
  1024  				},
  1025  				Filters: []*v3listenerpb.Filter{
  1026  					{
  1027  						Name: "filter-1",
  1028  						ConfigType: &v3listenerpb.Filter_TypedConfig{
  1029  							TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
  1030  								RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
  1031  									RouteConfig: &v3routepb.RouteConfiguration{
  1032  										Name: "routeName",
  1033  										VirtualHosts: []*v3routepb.VirtualHost{{
  1034  											// Incoming RPC's will try and match to Virtual Hosts based on their :authority header.
  1035  											// Thus, incoming RPC's will never match to a Virtual Host (server side requires matching
  1036  											// to a VH/Route of type Non Forwarding Action to proceed normally), and all incoming RPC's
  1037  											// with this route configuration will be denied.
  1038  											Domains: []string{"will-never-match"},
  1039  											Routes: []*v3routepb.Route{{
  1040  												Match: &v3routepb.RouteMatch{
  1041  													PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"},
  1042  												},
  1043  												Action: &v3routepb.Route_NonForwardingAction{},
  1044  											}}}}},
  1045  								},
  1046  								HttpFilters: []*v3httppb.HttpFilter{e2e.RouterHTTPFilter},
  1047  							}),
  1048  						},
  1049  					},
  1050  				},
  1051  			},
  1052  			{
  1053  				Name: "v6-wildcard",
  1054  				FilterChainMatch: &v3listenerpb.FilterChainMatch{
  1055  					PrefixRanges: []*v3corepb.CidrRange{
  1056  						{
  1057  							AddressPrefix: "::",
  1058  							PrefixLen: &wrapperspb.UInt32Value{
  1059  								Value: uint32(0),
  1060  							},
  1061  						},
  1062  					},
  1063  					SourceType: v3listenerpb.FilterChainMatch_SAME_IP_OR_LOOPBACK,
  1064  					SourcePrefixRanges: []*v3corepb.CidrRange{
  1065  						{
  1066  							AddressPrefix: "::",
  1067  							PrefixLen: &wrapperspb.UInt32Value{
  1068  								Value: uint32(0),
  1069  							},
  1070  						},
  1071  					},
  1072  				},
  1073  				Filters: []*v3listenerpb.Filter{
  1074  					{
  1075  						Name: "filter-1",
  1076  						ConfigType: &v3listenerpb.Filter_TypedConfig{
  1077  							TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
  1078  								RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
  1079  									RouteConfig: &v3routepb.RouteConfiguration{
  1080  										Name: "routeName",
  1081  										VirtualHosts: []*v3routepb.VirtualHost{{
  1082  											// Incoming RPC's will try and match to Virtual Hosts based on their :authority header.
  1083  											// Thus, incoming RPC's will never match to a Virtual Host (server side requires matching
  1084  											// to a VH/Route of type Non Forwarding Action to proceed normally), and all incoming RPC's
  1085  											// with this route configuration will be denied.
  1086  											Domains: []string{"will-never-match"},
  1087  											Routes: []*v3routepb.Route{{
  1088  												Match: &v3routepb.RouteMatch{
  1089  													PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"},
  1090  												},
  1091  												Action: &v3routepb.Route_NonForwardingAction{},
  1092  											}}}}},
  1093  								},
  1094  								HttpFilters: []*v3httppb.HttpFilter{e2e.RouterHTTPFilter},
  1095  							}),
  1096  						},
  1097  					},
  1098  				},
  1099  			},
  1100  		},
  1101  	}
  1102  }
  1103  
  1104  func (s) TestRBACToggledOn_WithBadRouteConfiguration(t *testing.T) {
  1105  	// Turn RBAC support on.
  1106  	oldRBAC := envconfig.XDSRBAC
  1107  	envconfig.XDSRBAC = true
  1108  	defer func() {
  1109  		envconfig.XDSRBAC = oldRBAC
  1110  	}()
  1111  
  1112  	managementServer, nodeID, bootstrapContents, resolver, cleanup1 := setupManagementServer(t)
  1113  	defer cleanup1()
  1114  
  1115  	lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
  1116  	defer cleanup2()
  1117  
  1118  	host, port, err := hostPortFromListener(lis)
  1119  	if err != nil {
  1120  		t.Fatalf("failed to retrieve host and port of server: %v", err)
  1121  	}
  1122  	const serviceName = "my-service-fallback"
  1123  
  1124  	// The inbound listener needs a route table that will never match on a VH,
  1125  	// and thus shouldn't allow incoming RPC's to proceed.
  1126  	resources := e2e.DefaultClientResources(e2e.ResourceParams{
  1127  		DialTarget: serviceName,
  1128  		NodeID:     nodeID,
  1129  		Host:       host,
  1130  		Port:       port,
  1131  		SecLevel:   e2e.SecurityLevelNone,
  1132  	})
  1133  	// Since RBAC support is turned ON, all the RPC's should get denied with
  1134  	// status code Unavailable due to not matching to a route of type Non
  1135  	// Forwarding Action (Route Table not configured properly).
  1136  	inboundLis := serverListenerWithBadRouteConfiguration(host, port)
  1137  	resources.Listeners = append(resources.Listeners, inboundLis)
  1138  
  1139  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
  1140  	defer cancel()
  1141  	// Setup the management server with client and server-side resources.
  1142  	if err := managementServer.Update(ctx, resources); err != nil {
  1143  		t.Fatal(err)
  1144  	}
  1145  
  1146  	cc, err := grpc.DialContext(ctx, fmt.Sprintf("xds:///%s", serviceName), grpc.WithInsecure(), grpc.WithResolvers(resolver))
  1147  	if err != nil {
  1148  		t.Fatalf("failed to dial local test server: %v", err)
  1149  	}
  1150  	defer cc.Close()
  1151  
  1152  	client := testpb.NewTestServiceClient(cc)
  1153  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}); status.Code(err) != codes.Unavailable {
  1154  		t.Fatalf("EmptyCall() returned err with status: %v, if RBAC is disabled all RPC's should proceed as normal", status.Code(err))
  1155  	}
  1156  	if _, err := client.UnaryCall(ctx, &testpb.SimpleRequest{}); status.Code(err) != codes.Unavailable {
  1157  		t.Fatalf("UnaryCall() returned err with status: %v, if RBAC is disabled all RPC's should proceed as normal", status.Code(err))
  1158  	}
  1159  }
  1160  
  1161  func (s) TestRBACToggledOff_WithBadRouteConfiguration(t *testing.T) {
  1162  	// Turn RBAC support off.
  1163  	oldRBAC := envconfig.XDSRBAC
  1164  	envconfig.XDSRBAC = false
  1165  	defer func() {
  1166  		envconfig.XDSRBAC = oldRBAC
  1167  	}()
  1168  
  1169  	managementServer, nodeID, bootstrapContents, resolver, cleanup1 := setupManagementServer(t)
  1170  	defer cleanup1()
  1171  
  1172  	lis, cleanup2 := setupGRPCServer(t, bootstrapContents)
  1173  	defer cleanup2()
  1174  
  1175  	host, port, err := hostPortFromListener(lis)
  1176  	if err != nil {
  1177  		t.Fatalf("failed to retrieve host and port of server: %v", err)
  1178  	}
  1179  	const serviceName = "my-service-fallback"
  1180  
  1181  	// The inbound listener needs a route table that will never match on a VH,
  1182  	// and thus shouldn't allow incoming RPC's to proceed.
  1183  	resources := e2e.DefaultClientResources(e2e.ResourceParams{
  1184  		DialTarget: serviceName,
  1185  		NodeID:     nodeID,
  1186  		Host:       host,
  1187  		Port:       port,
  1188  		SecLevel:   e2e.SecurityLevelNone,
  1189  	})
  1190  	// This bad route configuration shouldn't affect incoming RPC's from
  1191  	// proceeding as normal, as the configuration shouldn't be parsed due to the
  1192  	// RBAC Environment variable not being set to true.
  1193  	inboundLis := serverListenerWithBadRouteConfiguration(host, port)
  1194  	resources.Listeners = append(resources.Listeners, inboundLis)
  1195  
  1196  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
  1197  	defer cancel()
  1198  	// Setup the management server with client and server-side resources.
  1199  	if err := managementServer.Update(ctx, resources); err != nil {
  1200  		t.Fatal(err)
  1201  	}
  1202  
  1203  	cc, err := grpc.DialContext(ctx, fmt.Sprintf("xds:///%s", serviceName), grpc.WithInsecure(), grpc.WithResolvers(resolver))
  1204  	if err != nil {
  1205  		t.Fatalf("failed to dial local test server: %v", err)
  1206  	}
  1207  	defer cc.Close()
  1208  
  1209  	client := testpb.NewTestServiceClient(cc)
  1210  	if _, err := client.EmptyCall(ctx, &testpb.Empty{}); status.Code(err) != codes.OK {
  1211  		t.Fatalf("EmptyCall() returned err with status: %v, if RBAC is disabled all RPC's should proceed as normal", status.Code(err))
  1212  	}
  1213  	if _, err := client.UnaryCall(ctx, &testpb.SimpleRequest{}); status.Code(err) != codes.OK {
  1214  		t.Fatalf("UnaryCall() returned err with status: %v, if RBAC is disabled all RPC's should proceed as normal", status.Code(err))
  1215  	}
  1216  }