From 78a14986eb48d484c61d2869e7e7d3071ea0acc1 Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Thu, 18 Dec 2025 18:48:44 +0000 Subject: [PATCH 1/9] clusterimpl changes --- internal/testutils/xds/e2e/clientresources.go | 3 + .../xds/balancer/clusterimpl/clusterimpl.go | 6 + internal/xds/balancer/clusterimpl/picker.go | 16 +- .../clusterimpl/tests/balancer_test.go | 233 ++++++++++++++++++ .../xdsclient/xdsresource/unmarshal_eds.go | 4 +- stream.go | 9 +- 6 files changed, 265 insertions(+), 6 deletions(-) diff --git a/internal/testutils/xds/e2e/clientresources.go b/internal/testutils/xds/e2e/clientresources.go index be375d40851c..6ce8402e1958 100644 --- a/internal/testutils/xds/e2e/clientresources.go +++ b/internal/testutils/xds/e2e/clientresources.go @@ -650,6 +650,8 @@ type BackendOptions struct { HealthStatus v3corepb.HealthStatus // Weight sets the backend weight. Defaults to 1. Weight uint32 + // Hostname sets the endpoint hostname for authority rewriting. + Hostname string // Metadata sets the LB endpoint metadata (envoy.lb FilterMetadata field). // See https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#envoy-v3-api-msg-config-core-v3-metadata Metadata map[string]any @@ -721,6 +723,7 @@ func EndpointResourceWithOptions(opts EndpointOptions) *v3endpointpb.ClusterLoad PortSpecifier: &v3corepb.SocketAddress_PortValue{PortValue: b.Ports[0]}, }, }}, + Hostname: b.Hostname, AdditionalAddresses: additionalAddresses, }}, HealthStatus: b.HealthStatus, diff --git a/internal/xds/balancer/clusterimpl/clusterimpl.go b/internal/xds/balancer/clusterimpl/clusterimpl.go index b5dc77371548..f3aa49d00d7f 100644 --- a/internal/xds/balancer/clusterimpl/clusterimpl.go +++ b/internal/xds/balancer/clusterimpl/clusterimpl.go @@ -45,6 +45,7 @@ import ( "google.golang.org/grpc/internal/xds/clients" "google.golang.org/grpc/internal/xds/clients/lrsclient" "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/internal/xds/xdsclient/xdsresource" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" ) @@ -420,6 +421,8 @@ type scWrapper struct { // locality needs to be atomic because it can be updated while being read by // the picker. locality atomic.Pointer[clients.Locality] + + hostname string } func (scw *scWrapper) updateLocalityID(lID clients.Locality) { @@ -442,6 +445,9 @@ func (b *clusterImplBalancer) NewSubConn(addrs []resolver.Address, opts balancer } var sc balancer.SubConn scw := &scWrapper{} + if len(addrs) > 0 { + scw.hostname = xdsresource.HostnameFromEndpoint(addrs[0]) + } oldListener := opts.StateListener opts.StateListener = func(state balancer.SubConnState) { b.updateSubConnState(sc, state, oldListener) diff --git a/internal/xds/balancer/clusterimpl/picker.go b/internal/xds/balancer/clusterimpl/picker.go index d766a09a6963..de1aabdf5586 100644 --- a/internal/xds/balancer/clusterimpl/picker.go +++ b/internal/xds/balancer/clusterimpl/picker.go @@ -31,6 +31,7 @@ import ( xdsinternal "google.golang.org/grpc/internal/xds" "google.golang.org/grpc/internal/xds/clients" "google.golang.org/grpc/internal/xds/xdsclient" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" ) @@ -145,6 +146,14 @@ func (d *picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) { // If locality ID isn't found in the wrapper, an empty locality ID will // be used. lID = scw.localityID() + + if scw.hostname != "" && autoHostRewrite(info.Ctx) { + if pr.Metadata == nil { + pr.Metadata = metadata.Pairs(":authority", scw.hostname) + } else { + pr.Metadata.Set(":authority", scw.hostname) + } + } } if err != nil { @@ -201,8 +210,11 @@ type autoHostRewriteKey struct{} // autoHostRewrite retrieves the autoHostRewrite value from the provided context. func autoHostRewrite(ctx context.Context) bool { - v, _ := ctx.Value(autoHostRewriteKey{}).(bool) - return v + v := ctx.Value(autoHostRewriteKey{}) + if v == nil { + return false + } + return v.(bool) } // AutoHostRewriteForTesting returns the value of autoHostRewrite field; diff --git a/internal/xds/balancer/clusterimpl/tests/balancer_test.go b/internal/xds/balancer/clusterimpl/tests/balancer_test.go index 2bb398845458..bad5a62a93d3 100644 --- a/internal/xds/balancer/clusterimpl/tests/balancer_test.go +++ b/internal/xds/balancer/clusterimpl/tests/balancer_test.go @@ -20,6 +20,7 @@ package clusterimpl_test import ( "context" + "crypto/tls" "encoding/json" "errors" "fmt" @@ -38,19 +39,24 @@ import ( "google.golang.org/grpc/balancer/pickfirst" "google.golang.org/grpc/codes" "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal" "google.golang.org/grpc/internal/balancer/stub" + "google.golang.org/grpc/internal/envconfig" "google.golang.org/grpc/internal/grpctest" "google.golang.org/grpc/internal/stubserver" "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/testutils/xds/fakeserver" + "google.golang.org/grpc/internal/xds/bootstrap" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" "google.golang.org/grpc/resolver" "google.golang.org/grpc/resolver/manual" "google.golang.org/grpc/serviceconfig" "google.golang.org/grpc/status" + "google.golang.org/grpc/testdata" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/wrapperspb" @@ -1316,3 +1322,230 @@ func (s) TestFailedToParseChildPolicyConfig(t *testing.T) { t.Fatal("EmptyCall RPC succeeded when expected to fail") } } + +// setupManagementServerAndResolver sets up an xDS management server and returns +// the resolver builder. +func setupManagementServerAndResolver(t *testing.T) (*e2e.ManagementServer, resolver.Builder, string) { + t.Helper() + + testutils.SetEnvConfig(t, &envconfig.XDSAuthorityRewrite, true) + nodeID := uuid.New().String() + mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{SupportLoadReportingService: true}) + + opts := bootstrap.ConfigOptionsForTesting{ + Servers: []byte(fmt.Sprintf(`[{ + "server_uri": %q, + "channel_creds": [{"type": "insecure"}], + "server_features": ["trusted_xds_server"] + }]`, mgmtServer.Address)), + Node: []byte(fmt.Sprintf(`{"id": "%s"}`, nodeID)), + } + + contents, err := bootstrap.NewContentsForTesting(opts) + if err != nil { + t.Fatalf("Failed to create bootstrap configuration: %v", err) + } + testutils.CreateBootstrapFileForTesting(t, contents) + + // Create an xDS resolver with the above bootstrap configuration. + if internal.NewXDSResolverWithConfigForTesting == nil { + t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") + } + resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(contents) + if err != nil { + t.Fatalf("Failed to create xDS resolver for testing: %v", err) + } + + return mgmtServer, resolverBuilder, nodeID +} + +// configureXDSResources configures the management server with a route that +// enables auto_host_rewrite and an endpoint with the specified hostname. +func configureXDSResources(ctx context.Context, t *testing.T, mgmtServer *e2e.ManagementServer, nodeID string, serverAddr string, endpointHostname string) { + t.Helper() + + const ( + serviceName = "my-test-xds-service" + routeName = "route-my-test-xds-service" + clusterName = "cluster-my-test-xds-service" + endpointName = "endpoints-my-test-xds-service" + ) + + resources := e2e.DefaultClientResources(e2e.ResourceParams{ + DialTarget: serviceName, + NodeID: nodeID, + Host: "localhost", + Port: testutils.ParsePort(t, serverAddr), + SecLevel: e2e.SecurityLevelNone, + }) + + resources.Endpoints = []*v3endpointpb.ClusterLoadAssignment{ + e2e.EndpointResourceWithOptions(e2e.EndpointOptions{ + ClusterName: endpointName, + Host: "localhost", + Localities: []e2e.LocalityOptions{ + { + Backends: []e2e.BackendOptions{{ + Ports: []uint32{testutils.ParsePort(t, serverAddr)}, + Hostname: endpointHostname, + }}, + Weight: 1, + }, + }, + }), + } + + resources.Routes = []*v3routepb.RouteConfiguration{{ + Name: routeName, + VirtualHosts: []*v3routepb.VirtualHost{{ + Domains: []string{serviceName, "x.test.example.com"}, + Routes: []*v3routepb.Route{{ + Match: &v3routepb.RouteMatch{PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"}}, + Action: &v3routepb.Route_Route{Route: &v3routepb.RouteAction{ + ClusterSpecifier: &v3routepb.RouteAction_WeightedClusters{WeightedClusters: &v3routepb.WeightedCluster{ + Clusters: []*v3routepb.WeightedCluster_ClusterWeight{ + { + Name: clusterName, + Weight: &wrapperspb.UInt32Value{Value: 100}, + }, + }, + }}, + HostRewriteSpecifier: &v3routepb.RouteAction_AutoHostRewrite{ + AutoHostRewrite: &wrapperspb.BoolValue{Value: true}, + }, + }}, + }}, + }}, + }} + + if err := mgmtServer.Update(ctx, resources); err != nil { + t.Fatal(err) + } +} + +// TestAuthorityOverriding verifies that the :authority header is correctly +// rewritten to the endpoint's hostname. Also verifies that CallAuthority +// call option takes precedence. +func (s) TestAuthorityOverriding(t *testing.T) { + mgmtServer, resolverBuilder, nodeID := setupManagementServerAndResolver(t) + + authorityCh := make(chan string, 1) + + // Start a server backend exposing the test service. + f := &stubserver.StubServer{ + FullDuplexCallF: func(stream testgrpc.TestService_FullDuplexCallServer) error { + if md, ok := metadata.FromIncomingContext(stream.Context()); ok { + if authVals := md.Get(":authority"); len(authVals) > 0 { + authorityCh <- authVals[0] + } + } + return nil + }, + } + server := stubserver.StartTestService(t, f) + defer server.Stop() + + const rewrittenAuthority = "rewritten.example.com" + + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + configureXDSResources(ctx, t, mgmtServer, nodeID, server.Address, rewrittenAuthority) + + // Create a ClientConn and make a successful RPC. + cc, err := grpc.NewClient("xds:///my-test-xds-service", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolverBuilder)) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + defer cc.Close() + + client := testgrpc.NewTestServiceClient(cc) + if _, err := client.FullDuplexCall(ctx); err != nil { + t.Fatalf("client.FullDuplexCall() failed: %v", err) + } + + select { + case gotAuth := <-authorityCh: + if gotAuth != rewrittenAuthority { + t.Errorf("invalid authority got: %q, want: %q", gotAuth, rewrittenAuthority) + } + case <-ctx.Done(): + t.Fatalf("Timeout waiting for successful RPC after authority rewriting.") + } + + // The authority specified via the `CallAuthority` CallOption takes the + // highest precedence when determining the `:authority` header. + userAuth := "user-override.com" + if _, err := client.FullDuplexCall(ctx, grpc.CallAuthority(userAuth)); err != nil { + t.Fatalf("client.FullDuplexCall() failed: %v", err) + } + + select { + case got := <-authorityCh: + if got != userAuth { + t.Errorf("Server received authority %q, want %q (user override)", got, userAuth) + } + case <-ctx.Done(): + t.Fatalf("Timeout waiting for successful RPC.") + } +} + +// TestAuthorityOverridingWithTLS verifies the interaction between xDS Authority +// Rewriting and TLS Secure Naming. It ensures that when the :authority header +// is rewritten by the xDS picker, the new authority is correctly validated +// against the server's TLS certificate before the RPC proceeds. +func (s) TestAuthorityOverridingWithTLS(t *testing.T) { + mgmtServer, resolverBuilder, nodeID := setupManagementServerAndResolver(t) + + serverCert, err := tls.LoadX509KeyPair(testdata.Path("x509/server1_cert.pem"), testdata.Path("x509/server1_key.pem")) + if err != nil { + t.Fatalf("Failed to load server key pair: %v", err) + } + + const rewrittenAuthority = "x.test.example.com" + clientCreds, err := credentials.NewClientTLSFromFile(testdata.Path("x509/server_ca_cert.pem"), rewrittenAuthority) + if err != nil { + t.Fatalf("Failed to create client credentials: %v", err) + } + + authorityCh := make(chan string, 1) + // Start TLS Server + f := &stubserver.StubServer{ + FullDuplexCallF: func(stream testgrpc.TestService_FullDuplexCallServer) error { + if md, ok := metadata.FromIncomingContext(stream.Context()); ok { + if authVals := md.Get(":authority"); len(authVals) > 0 { + authorityCh <- authVals[0] + } + } + return nil + }, + } + if err := f.StartServer(grpc.Creds(credentials.NewServerTLSFromCert(&serverCert))); err != nil { + t.Fatalf("Failed to start TLS server: %v", err) + } + defer f.Stop() + + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + configureXDSResources(ctx, t, mgmtServer, nodeID, f.Address, rewrittenAuthority) + + // Create ClientConn with TLS + cc, err := grpc.NewClient("xds:///my-test-xds-service", grpc.WithTransportCredentials(clientCreds), grpc.WithResolvers(resolverBuilder)) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + defer cc.Close() + + client := testgrpc.NewTestServiceClient(cc) + if _, err := client.FullDuplexCall(ctx); err != nil { + t.Fatalf("client.FullDuplexCall() failed: %v", err) + } + + select { + case gotAuth := <-authorityCh: + if gotAuth != rewrittenAuthority { + t.Errorf("invalid authority got: %q, want: %q", gotAuth, rewrittenAuthority) + } + case <-ctx.Done(): + t.Fatalf("Timeout waiting for successful RPC after authority rewriting.") + } +} diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_eds.go b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go index 4ec133249bbe..edea8bd63480 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_eds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go @@ -53,8 +53,8 @@ func setHostname(endpoint resolver.Endpoint, hostname string) resolver.Endpoint // HostnameFromEndpoint returns the hostname attribute of endpoint. If this // attribute is not set, it returns the empty string. -func HostnameFromEndpoint(endpoint resolver.Endpoint) string { - hostname, _ := endpoint.Attributes.Value(hostnameKeyType{}).(string) +func HostnameFromEndpoint(addr resolver.Address) string { + hostname, _ := addr.BalancerAttributes.Value(hostnameKeyType{}).(string) return hostname } diff --git a/stream.go b/stream.go index ec9577b2789c..33af2c0c9f42 100644 --- a/stream.go +++ b/stream.go @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -537,8 +537,13 @@ func (a *csAttempt) newStream() error { md, _ := metadata.FromOutgoingContext(a.ctx) md = metadata.Join(md, a.pickResult.Metadata) a.ctx = metadata.NewOutgoingContext(a.ctx, md) - } + if cs.callInfo.authority == "" { + if authMD := a.pickResult.Metadata.Get(":authority"); len(authMD) > 0 { + cs.callHdr.Authority = authMD[0] + } + } + } s, err := a.transport.NewStream(a.ctx, cs.callHdr) if err != nil { nse, ok := err.(*transport.NewStreamError) From 4ba52d77c320499bb7a1da65ca22a93940334ade Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Fri, 19 Dec 2025 12:29:12 +0000 Subject: [PATCH 2/9] resolving comments --- .../xds/balancer/clusterimpl/clusterimpl.go | 2 +- internal/xds/balancer/clusterimpl/picker.go | 7 +- .../clusterimpl/tests/balancer_test.go | 131 +++++++----------- .../xdsclient/xdsresource/unmarshal_eds.go | 6 +- stream.go | 5 +- 5 files changed, 60 insertions(+), 91 deletions(-) diff --git a/internal/xds/balancer/clusterimpl/clusterimpl.go b/internal/xds/balancer/clusterimpl/clusterimpl.go index f3aa49d00d7f..c45c39859a0c 100644 --- a/internal/xds/balancer/clusterimpl/clusterimpl.go +++ b/internal/xds/balancer/clusterimpl/clusterimpl.go @@ -446,7 +446,7 @@ func (b *clusterImplBalancer) NewSubConn(addrs []resolver.Address, opts balancer var sc balancer.SubConn scw := &scWrapper{} if len(addrs) > 0 { - scw.hostname = xdsresource.HostnameFromEndpoint(addrs[0]) + scw.hostname = xdsresource.HostnameFromAddress(addrs[0]) } oldListener := opts.StateListener opts.StateListener = func(state balancer.SubConnState) { diff --git a/internal/xds/balancer/clusterimpl/picker.go b/internal/xds/balancer/clusterimpl/picker.go index de1aabdf5586..c60dda6b5a42 100644 --- a/internal/xds/balancer/clusterimpl/picker.go +++ b/internal/xds/balancer/clusterimpl/picker.go @@ -210,11 +210,8 @@ type autoHostRewriteKey struct{} // autoHostRewrite retrieves the autoHostRewrite value from the provided context. func autoHostRewrite(ctx context.Context) bool { - v := ctx.Value(autoHostRewriteKey{}) - if v == nil { - return false - } - return v.(bool) + v, _ := ctx.Value(autoHostRewriteKey{}).(bool) + return v } // AutoHostRewriteForTesting returns the value of autoHostRewrite field; diff --git a/internal/xds/balancer/clusterimpl/tests/balancer_test.go b/internal/xds/balancer/clusterimpl/tests/balancer_test.go index bad5a62a93d3..412970da4fae 100644 --- a/internal/xds/balancer/clusterimpl/tests/balancer_test.go +++ b/internal/xds/balancer/clusterimpl/tests/balancer_test.go @@ -21,11 +21,13 @@ package clusterimpl_test import ( "context" "crypto/tls" + "crypto/x509" "encoding/json" "errors" "fmt" "math" "net" + "os" "strconv" "strings" "sync/atomic" @@ -101,7 +103,6 @@ func (s) TestConfigUpdateWithSameLoadReportingServerConfig(t *testing.T) { // Create bootstrap configuration pointing to the above management server. nodeID := uuid.New().String() bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - testutils.CreateBootstrapFileForTesting(t, bc) // Create an xDS resolver with the above bootstrap configuration. if internal.NewXDSResolverWithConfigForTesting == nil { @@ -383,7 +384,6 @@ func (s) TestCircuitBreaking(t *testing.T) { // Create bootstrap configuration pointing to the above management server. nodeID := uuid.New().String() bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - testutils.CreateBootstrapFileForTesting(t, bc) // Create an xDS resolver with the above bootstrap configuration. if internal.NewXDSResolverWithConfigForTesting == nil { @@ -580,7 +580,6 @@ func (s) TestDropByCategory(t *testing.T) { // Create bootstrap configuration pointing to the above management server. nodeID := uuid.New().String() bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - testutils.CreateBootstrapFileForTesting(t, bc) // Create an xDS resolver with the above bootstrap configuration. if internal.NewXDSResolverWithConfigForTesting == nil { @@ -723,7 +722,6 @@ func (s) TestCircuitBreakingLogicalDNS(t *testing.T) { // Create bootstrap configuration pointing to the above management server. nodeID := uuid.New().String() bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - testutils.CreateBootstrapFileForTesting(t, bc) // Create an xDS resolver with the above bootstrap configuration. if internal.NewXDSResolverWithConfigForTesting == nil { @@ -842,7 +840,6 @@ func (s) TestLRSLogicalDNS(t *testing.T) { // Create bootstrap configuration pointing to the above management server. nodeID := uuid.New().String() bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - testutils.CreateBootstrapFileForTesting(t, bc) // Create an xDS resolver with the above bootstrap configuration. if internal.NewXDSResolverWithConfigForTesting == nil { @@ -934,7 +931,6 @@ func (s) TestReResolutionAfterTransientFailure(t *testing.T) { // Create bootstrap configuration pointing to the above management server. nodeID := uuid.New().String() bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - testutils.CreateBootstrapFileForTesting(t, bc) // Create an xDS resolver with the above bootstrap configuration. if internal.NewXDSResolverWithConfigForTesting == nil { @@ -1054,7 +1050,6 @@ func (s) TestUpdateLRSServerToNil(t *testing.T) { // Create bootstrap configuration pointing to the above management server. nodeID := uuid.New().String() bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - testutils.CreateBootstrapFileForTesting(t, bc) // Create an xDS resolver with the above bootstrap configuration. if internal.NewXDSResolverWithConfigForTesting == nil { @@ -1141,7 +1136,6 @@ func (s) TestChildPolicyChangeOnConfigUpdate(t *testing.T) { // Create bootstrap configuration pointing to the above management server. nodeID := uuid.New().String() bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - testutils.CreateBootstrapFileForTesting(t, bc) // Create an xDS resolver with the above bootstrap configuration. if internal.NewXDSResolverWithConfigForTesting == nil { @@ -1264,7 +1258,6 @@ func (s) TestFailedToParseChildPolicyConfig(t *testing.T) { // Create bootstrap configuration pointing to the above management server. nodeID := uuid.New().String() bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - testutils.CreateBootstrapFileForTesting(t, bc) // Create an xDS resolver with the above bootstrap configuration. if internal.NewXDSResolverWithConfigForTesting == nil { @@ -1324,13 +1317,12 @@ func (s) TestFailedToParseChildPolicyConfig(t *testing.T) { } // setupManagementServerAndResolver sets up an xDS management server and returns -// the resolver builder. +// the management server, resolver builder and Node ID. func setupManagementServerAndResolver(t *testing.T) (*e2e.ManagementServer, resolver.Builder, string) { t.Helper() - testutils.SetEnvConfig(t, &envconfig.XDSAuthorityRewrite, true) nodeID := uuid.New().String() - mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{SupportLoadReportingService: true}) + mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{}) opts := bootstrap.ConfigOptionsForTesting{ Servers: []byte(fmt.Sprintf(`[{ @@ -1345,7 +1337,6 @@ func setupManagementServerAndResolver(t *testing.T) (*e2e.ManagementServer, reso if err != nil { t.Fatalf("Failed to create bootstrap configuration: %v", err) } - testutils.CreateBootstrapFileForTesting(t, contents) // Create an xDS resolver with the above bootstrap configuration. if internal.NewXDSResolverWithConfigForTesting == nil { @@ -1379,44 +1370,13 @@ func configureXDSResources(ctx context.Context, t *testing.T, mgmtServer *e2e.Ma SecLevel: e2e.SecurityLevelNone, }) - resources.Endpoints = []*v3endpointpb.ClusterLoadAssignment{ - e2e.EndpointResourceWithOptions(e2e.EndpointOptions{ - ClusterName: endpointName, - Host: "localhost", - Localities: []e2e.LocalityOptions{ - { - Backends: []e2e.BackendOptions{{ - Ports: []uint32{testutils.ParsePort(t, serverAddr)}, - Hostname: endpointHostname, - }}, - Weight: 1, - }, - }, - }), - } + // Set the endpoint hostname for authority rewriting. + resources.Endpoints[0].Endpoints[0].LbEndpoints[0].GetEndpoint().Hostname = endpointHostname - resources.Routes = []*v3routepb.RouteConfiguration{{ - Name: routeName, - VirtualHosts: []*v3routepb.VirtualHost{{ - Domains: []string{serviceName, "x.test.example.com"}, - Routes: []*v3routepb.Route{{ - Match: &v3routepb.RouteMatch{PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"}}, - Action: &v3routepb.Route_Route{Route: &v3routepb.RouteAction{ - ClusterSpecifier: &v3routepb.RouteAction_WeightedClusters{WeightedClusters: &v3routepb.WeightedCluster{ - Clusters: []*v3routepb.WeightedCluster_ClusterWeight{ - { - Name: clusterName, - Weight: &wrapperspb.UInt32Value{Value: 100}, - }, - }, - }}, - HostRewriteSpecifier: &v3routepb.RouteAction_AutoHostRewrite{ - AutoHostRewrite: &wrapperspb.BoolValue{Value: true}, - }, - }}, - }}, - }}, - }} + // Modify the route to enable AutoHostRewrite. + resources.Routes[0].VirtualHosts[0].Routes[0].GetRoute().HostRewriteSpecifier = &v3routepb.RouteAction_AutoHostRewrite{ + AutoHostRewrite: &wrapperspb.BoolValue{Value: true}, + } if err := mgmtServer.Update(ctx, resources); err != nil { t.Fatal(err) @@ -1427,29 +1387,29 @@ func configureXDSResources(ctx context.Context, t *testing.T, mgmtServer *e2e.Ma // rewritten to the endpoint's hostname. Also verifies that CallAuthority // call option takes precedence. func (s) TestAuthorityOverriding(t *testing.T) { + testutils.SetEnvConfig(t, &envconfig.XDSAuthorityRewrite, true) mgmtServer, resolverBuilder, nodeID := setupManagementServerAndResolver(t) - authorityCh := make(chan string, 1) - // Start a server backend exposing the test service. + authorityCh := make(chan string, 1) f := &stubserver.StubServer{ - FullDuplexCallF: func(stream testgrpc.TestService_FullDuplexCallServer) error { - if md, ok := metadata.FromIncomingContext(stream.Context()); ok { + EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) { + if md, ok := metadata.FromIncomingContext(ctx); ok { if authVals := md.Get(":authority"); len(authVals) > 0 { authorityCh <- authVals[0] } } - return nil + return &testpb.Empty{}, nil }, } server := stubserver.StartTestService(t, f) defer server.Stop() - const rewrittenAuthority = "rewritten.example.com" + const xdsAuthorityOverride = "rewritten.example.com" ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel() - configureXDSResources(ctx, t, mgmtServer, nodeID, server.Address, rewrittenAuthority) + configureXDSResources(ctx, t, mgmtServer, nodeID, server.Address, xdsAuthorityOverride) // Create a ClientConn and make a successful RPC. cc, err := grpc.NewClient("xds:///my-test-xds-service", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolverBuilder)) @@ -1459,14 +1419,14 @@ func (s) TestAuthorityOverriding(t *testing.T) { defer cc.Close() client := testgrpc.NewTestServiceClient(cc) - if _, err := client.FullDuplexCall(ctx); err != nil { - t.Fatalf("client.FullDuplexCall() failed: %v", err) + if _, err := client.EmptyCall(ctx, &testpb.Empty{}); err != nil { + t.Fatalf("client.EmptyCall() failed: %v", err) } select { case gotAuth := <-authorityCh: - if gotAuth != rewrittenAuthority { - t.Errorf("invalid authority got: %q, want: %q", gotAuth, rewrittenAuthority) + if gotAuth != xdsAuthorityOverride { + t.Errorf("invalid authority got: %q, want: %q", gotAuth, xdsAuthorityOverride) } case <-ctx.Done(): t.Fatalf("Timeout waiting for successful RPC after authority rewriting.") @@ -1474,15 +1434,15 @@ func (s) TestAuthorityOverriding(t *testing.T) { // The authority specified via the `CallAuthority` CallOption takes the // highest precedence when determining the `:authority` header. - userAuth := "user-override.com" - if _, err := client.FullDuplexCall(ctx, grpc.CallAuthority(userAuth)); err != nil { - t.Fatalf("client.FullDuplexCall() failed: %v", err) + userAuthorityOverride := "user-override.com" + if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.CallAuthority(userAuthorityOverride)); err != nil { + t.Fatalf("client.EmptyCall() failed: %v", err) } select { case got := <-authorityCh: - if got != userAuth { - t.Errorf("Server received authority %q, want %q (user override)", got, userAuth) + if got != userAuthorityOverride { + t.Errorf("Server received authority %q, want %q (user override)", got, userAuthorityOverride) } case <-ctx.Done(): t.Fatalf("Timeout waiting for successful RPC.") @@ -1491,9 +1451,10 @@ func (s) TestAuthorityOverriding(t *testing.T) { // TestAuthorityOverridingWithTLS verifies the interaction between xDS Authority // Rewriting and TLS Secure Naming. It ensures that when the :authority header -// is rewritten by the xDS picker, the new authority is correctly validated -// against the server's TLS certificate before the RPC proceeds. +// is rewritten by the clusterimpl picker, the new authority is correctly +// validated against the server's TLS certificate before the RPC proceeds. func (s) TestAuthorityOverridingWithTLS(t *testing.T) { + testutils.SetEnvConfig(t, &envconfig.XDSAuthorityRewrite, true) mgmtServer, resolverBuilder, nodeID := setupManagementServerAndResolver(t) serverCert, err := tls.LoadX509KeyPair(testdata.Path("x509/server1_cert.pem"), testdata.Path("x509/server1_key.pem")) @@ -1501,32 +1462,40 @@ func (s) TestAuthorityOverridingWithTLS(t *testing.T) { t.Fatalf("Failed to load server key pair: %v", err) } - const rewrittenAuthority = "x.test.example.com" - clientCreds, err := credentials.NewClientTLSFromFile(testdata.Path("x509/server_ca_cert.pem"), rewrittenAuthority) + pemData, err := os.ReadFile(testdata.Path("x509/client_ca_cert.pem")) if err != nil { - t.Fatalf("Failed to create client credentials: %v", err) + t.Fatalf("Failed to read client CA cert: %v", err) } + roots := x509.NewCertPool() + roots.AppendCertsFromPEM(pemData) + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{serverCert}, + ClientCAs: roots, + InsecureSkipVerify: true, + } + clientCreds := credentials.NewTLS(tlsConfig) + // Start a server backend exposing the test service. authorityCh := make(chan string, 1) - // Start TLS Server f := &stubserver.StubServer{ - FullDuplexCallF: func(stream testgrpc.TestService_FullDuplexCallServer) error { - if md, ok := metadata.FromIncomingContext(stream.Context()); ok { + EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) { + if md, ok := metadata.FromIncomingContext(ctx); ok { if authVals := md.Get(":authority"); len(authVals) > 0 { authorityCh <- authVals[0] } } - return nil + return &testpb.Empty{}, nil }, } if err := f.StartServer(grpc.Creds(credentials.NewServerTLSFromCert(&serverCert))); err != nil { - t.Fatalf("Failed to start TLS server: %v", err) + t.Fatalf("Failed to start the server: %v", err) } defer f.Stop() ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel() - configureXDSResources(ctx, t, mgmtServer, nodeID, f.Address, rewrittenAuthority) + const xdsAuthorityOverride = "x.test.example.com" + configureXDSResources(ctx, t, mgmtServer, nodeID, f.Address, xdsAuthorityOverride) // Create ClientConn with TLS cc, err := grpc.NewClient("xds:///my-test-xds-service", grpc.WithTransportCredentials(clientCreds), grpc.WithResolvers(resolverBuilder)) @@ -1536,14 +1505,14 @@ func (s) TestAuthorityOverridingWithTLS(t *testing.T) { defer cc.Close() client := testgrpc.NewTestServiceClient(cc) - if _, err := client.FullDuplexCall(ctx); err != nil { - t.Fatalf("client.FullDuplexCall() failed: %v", err) + if _, err := client.EmptyCall(ctx, &testpb.Empty{}); err != nil { + t.Fatalf("client.EmptyCall() failed: %v", err) } select { case gotAuth := <-authorityCh: - if gotAuth != rewrittenAuthority { - t.Errorf("invalid authority got: %q, want: %q", gotAuth, rewrittenAuthority) + if gotAuth != xdsAuthorityOverride { + t.Errorf("invalid authority got: %q, want: %q", gotAuth, xdsAuthorityOverride) } case <-ctx.Done(): t.Fatalf("Timeout waiting for successful RPC after authority rewriting.") diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_eds.go b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go index edea8bd63480..cee5ca98b5d2 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_eds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go @@ -51,9 +51,9 @@ func setHostname(endpoint resolver.Endpoint, hostname string) resolver.Endpoint return endpoint } -// HostnameFromEndpoint returns the hostname attribute of endpoint. If this -// attribute is not set, it returns the empty string. -func HostnameFromEndpoint(addr resolver.Address) string { +// HostnameFromAddress returns the hostname BalancerAttributes of Address. +// If this attribute is not set, it returns the empty string. +func HostnameFromAddress(addr resolver.Address) string { hostname, _ := addr.BalancerAttributes.Value(hostnameKeyType{}).(string) return hostname } diff --git a/stream.go b/stream.go index 33af2c0c9f42..b2699d8c9563 100644 --- a/stream.go +++ b/stream.go @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -538,6 +538,9 @@ func (a *csAttempt) newStream() error { md = metadata.Join(md, a.pickResult.Metadata) a.ctx = metadata.NewOutgoingContext(a.ctx, md) + // If the `CallAuthority` CallOption is not set, check if the LB picker + // has provided an authority override in the PickResult metadata and + // apply it, as specified in gRFC A81. if cs.callInfo.authority == "" { if authMD := a.pickResult.Metadata.Get(":authority"); len(authMD) > 0 { cs.callHdr.Authority = authMD[0] From 29ca7873d32ceb37713380e6c42fb5fc9135c62b Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Wed, 24 Dec 2025 16:06:32 +0000 Subject: [PATCH 3/9] resolving comments --- internal/testutils/xds/e2e/bootstrap.go | 3 +- .../balancer/cdsbalancer/cdsbalancer_test.go | 2 +- .../clusterimpl/tests/balancer_test.go | 151 +++++++++--------- .../xdsclient/tests/resource_update_test.go | 2 +- 4 files changed, 78 insertions(+), 80 deletions(-) diff --git a/internal/testutils/xds/e2e/bootstrap.go b/internal/testutils/xds/e2e/bootstrap.go index d902e94a5144..768d32b01c8f 100644 --- a/internal/testutils/xds/e2e/bootstrap.go +++ b/internal/testutils/xds/e2e/bootstrap.go @@ -133,7 +133,8 @@ func DefaultBootstrapContents(t *testing.T, nodeID, serverURI string) []byte { bs, err := bootstrap.NewContentsForTesting(bootstrap.ConfigOptionsForTesting{ Servers: []byte(fmt.Sprintf(`[{ "server_uri": "passthrough:///%s", - "channel_creds": [{"type": "insecure"}] + "channel_creds": [{"type": "insecure"}], + "server_features": ["trusted_xds_server"] }]`, serverURI)), Node: []byte(fmt.Sprintf(`{"id": "%s"}`, nodeID)), CertificateProviders: cpc, diff --git a/internal/xds/balancer/cdsbalancer/cdsbalancer_test.go b/internal/xds/balancer/cdsbalancer/cdsbalancer_test.go index 3bd1a49c73aa..00041bbd5a72 100644 --- a/internal/xds/balancer/cdsbalancer/cdsbalancer_test.go +++ b/internal/xds/balancer/cdsbalancer/cdsbalancer_test.go @@ -654,7 +654,7 @@ func (s) TestClusterUpdate_SuccessWithLRS(t *testing.T) { ServiceName: serviceName, EnableLRS: true, }) - lrsServerCfg, err := bootstrap.ServerConfigForTesting(bootstrap.ServerConfigTestingOptions{URI: fmt.Sprintf("passthrough:///%s", mgmtServer.Address)}) + lrsServerCfg, err := bootstrap.ServerConfigForTesting(bootstrap.ServerConfigTestingOptions{URI: fmt.Sprintf("passthrough:///%s", mgmtServer.Address), ServerFeatures: []string{"trusted_xds_server"}}) if err != nil { t.Fatalf("Failed to create LRS server config for testing: %v", err) } diff --git a/internal/xds/balancer/clusterimpl/tests/balancer_test.go b/internal/xds/balancer/clusterimpl/tests/balancer_test.go index 412970da4fae..f137d06fc8ee 100644 --- a/internal/xds/balancer/clusterimpl/tests/balancer_test.go +++ b/internal/xds/balancer/clusterimpl/tests/balancer_test.go @@ -21,13 +21,11 @@ package clusterimpl_test import ( "context" "crypto/tls" - "crypto/x509" "encoding/json" "errors" "fmt" "math" "net" - "os" "strconv" "strings" "sync/atomic" @@ -41,7 +39,6 @@ import ( "google.golang.org/grpc/balancer/pickfirst" "google.golang.org/grpc/codes" "google.golang.org/grpc/connectivity" - "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal" "google.golang.org/grpc/internal/balancer/stub" @@ -51,14 +48,12 @@ import ( "google.golang.org/grpc/internal/testutils" "google.golang.org/grpc/internal/testutils/xds/e2e" "google.golang.org/grpc/internal/testutils/xds/fakeserver" - "google.golang.org/grpc/internal/xds/bootstrap" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" "google.golang.org/grpc/resolver" "google.golang.org/grpc/resolver/manual" "google.golang.org/grpc/serviceconfig" "google.golang.org/grpc/status" - "google.golang.org/grpc/testdata" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/wrapperspb" @@ -71,6 +66,7 @@ import ( v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" v3pickfirstpb "github.com/envoyproxy/go-control-plane/envoy/extensions/load_balancing_policies/pick_first/v3" v3lrspb "github.com/envoyproxy/go-control-plane/envoy/service/load_stats/v3" + xdscreds "google.golang.org/grpc/credentials/xds" testgrpc "google.golang.org/grpc/interop/grpc_testing" testpb "google.golang.org/grpc/interop/grpc_testing" "google.golang.org/protobuf/types/known/structpb" @@ -1323,20 +1319,7 @@ func setupManagementServerAndResolver(t *testing.T) (*e2e.ManagementServer, reso nodeID := uuid.New().String() mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{}) - - opts := bootstrap.ConfigOptionsForTesting{ - Servers: []byte(fmt.Sprintf(`[{ - "server_uri": %q, - "channel_creds": [{"type": "insecure"}], - "server_features": ["trusted_xds_server"] - }]`, mgmtServer.Address)), - Node: []byte(fmt.Sprintf(`{"id": "%s"}`, nodeID)), - } - - contents, err := bootstrap.NewContentsForTesting(opts) - if err != nil { - t.Fatalf("Failed to create bootstrap configuration: %v", err) - } + contents := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) // Create an xDS resolver with the above bootstrap configuration. if internal.NewXDSResolverWithConfigForTesting == nil { @@ -1367,7 +1350,7 @@ func configureXDSResources(ctx context.Context, t *testing.T, mgmtServer *e2e.Ma NodeID: nodeID, Host: "localhost", Port: testutils.ParsePort(t, serverAddr), - SecLevel: e2e.SecurityLevelNone, + SecLevel: e2e.SecurityLevelMTLS, }) // Set the endpoint hostname for authority rewriting. @@ -1406,7 +1389,6 @@ func (s) TestAuthorityOverriding(t *testing.T) { defer server.Stop() const xdsAuthorityOverride = "rewritten.example.com" - ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel() configureXDSResources(ctx, t, mgmtServer, nodeID, server.Address, xdsAuthorityOverride) @@ -1434,7 +1416,7 @@ func (s) TestAuthorityOverriding(t *testing.T) { // The authority specified via the `CallAuthority` CallOption takes the // highest precedence when determining the `:authority` header. - userAuthorityOverride := "user-override.com" + const userAuthorityOverride = "user-override.com" if _, err := client.EmptyCall(ctx, &testpb.Empty{}, grpc.CallAuthority(userAuthorityOverride)); err != nil { t.Fatalf("client.EmptyCall() failed: %v", err) } @@ -1453,68 +1435,83 @@ func (s) TestAuthorityOverriding(t *testing.T) { // Rewriting and TLS Secure Naming. It ensures that when the :authority header // is rewritten by the clusterimpl picker, the new authority is correctly // validated against the server's TLS certificate before the RPC proceeds. +// Also check that RPC fails when the rewritten authority does not match the +// server's certificate due to secure naming validation. func (s) TestAuthorityOverridingWithTLS(t *testing.T) { - testutils.SetEnvConfig(t, &envconfig.XDSAuthorityRewrite, true) - mgmtServer, resolverBuilder, nodeID := setupManagementServerAndResolver(t) - - serverCert, err := tls.LoadX509KeyPair(testdata.Path("x509/server1_cert.pem"), testdata.Path("x509/server1_key.pem")) - if err != nil { - t.Fatalf("Failed to load server key pair: %v", err) - } - - pemData, err := os.ReadFile(testdata.Path("x509/client_ca_cert.pem")) - if err != nil { - t.Fatalf("Failed to read client CA cert: %v", err) - } - roots := x509.NewCertPool() - roots.AppendCertsFromPEM(pemData) - tlsConfig := &tls.Config{ - Certificates: []tls.Certificate{serverCert}, - ClientCAs: roots, - InsecureSkipVerify: true, + tests := []struct { + name string + xdsAuthorityOverride string + expectSuccess bool + }{ + { + name: "Valid_Authority_Rewrite", + xdsAuthorityOverride: "x.test.example.com", + expectSuccess: true, + }, + { + name: "Authority_Rewrite_Mismatch", + xdsAuthorityOverride: "xyz.exmaple.com", + expectSuccess: false, + }, } - clientCreds := credentials.NewTLS(tlsConfig) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + testutils.SetEnvConfig(t, &envconfig.XDSAuthorityRewrite, true) + mgmtServer, resolverBuilder, nodeID := setupManagementServerAndResolver(t) + + serverCreds := testutils.CreateServerTLSCredentials(t, tls.RequireAndVerifyClientCert) + + // Start a server backend exposing the test service. + authorityCh := make(chan string, 1) + f := &stubserver.StubServer{ + EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) { + if md, ok := metadata.FromIncomingContext(ctx); ok { + if authVals := md.Get(":authority"); len(authVals) > 0 { + authorityCh <- authVals[0] + } + } + return &testpb.Empty{}, nil + }, + } + f.StartServer(grpc.Creds(serverCreds)) + defer f.Stop() - // Start a server backend exposing the test service. - authorityCh := make(chan string, 1) - f := &stubserver.StubServer{ - EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) { - if md, ok := metadata.FromIncomingContext(ctx); ok { - if authVals := md.Get(":authority"); len(authVals) > 0 { - authorityCh <- authVals[0] - } + clientCreds, err := xdscreds.NewClientCredentials(xdscreds.ClientOptions{FallbackCreds: insecure.NewCredentials()}) + if err != nil { + t.Fatalf("Failed to create client credentials: %v", err) } - return &testpb.Empty{}, nil - }, - } - if err := f.StartServer(grpc.Creds(credentials.NewServerTLSFromCert(&serverCert))); err != nil { - t.Fatalf("Failed to start the server: %v", err) - } - defer f.Stop() - ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) - defer cancel() - const xdsAuthorityOverride = "x.test.example.com" - configureXDSResources(ctx, t, mgmtServer, nodeID, f.Address, xdsAuthorityOverride) + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + configureXDSResources(ctx, t, mgmtServer, nodeID, f.Address, test.xdsAuthorityOverride) - // Create ClientConn with TLS - cc, err := grpc.NewClient("xds:///my-test-xds-service", grpc.WithTransportCredentials(clientCreds), grpc.WithResolvers(resolverBuilder)) - if err != nil { - t.Fatalf("Failed to create client: %v", err) - } - defer cc.Close() + // Create ClientConn with TLS + cc, err := grpc.NewClient("xds:///my-test-xds-service", grpc.WithTransportCredentials(clientCreds), grpc.WithResolvers(resolverBuilder)) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + defer cc.Close() - client := testgrpc.NewTestServiceClient(cc) - if _, err := client.EmptyCall(ctx, &testpb.Empty{}); err != nil { - t.Fatalf("client.EmptyCall() failed: %v", err) - } + client := testgrpc.NewTestServiceClient(cc) + _, err = client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)) - select { - case gotAuth := <-authorityCh: - if gotAuth != xdsAuthorityOverride { - t.Errorf("invalid authority got: %q, want: %q", gotAuth, xdsAuthorityOverride) - } - case <-ctx.Done(): - t.Fatalf("Timeout waiting for successful RPC after authority rewriting.") + if test.expectSuccess { + if err != nil { + t.Fatalf("RPC failed unexpectedly: %v", err) + } + select { + case gotAuth := <-authorityCh: + if gotAuth != test.xdsAuthorityOverride { + t.Errorf("invalid authority got: %q, want: %q", gotAuth, test.xdsAuthorityOverride) + } + case <-ctx.Done(): + t.Fatalf("Timeout waiting for successful RPC after authority rewriting.") + } + } else { + if err == nil || !strings.Contains(err.Error(), "invalid authority") { + t.Fatal("RPC succeeded unexpectedly; expected TLS failure due to authority mismatch") + } + } + }) } } diff --git a/internal/xds/xdsclient/tests/resource_update_test.go b/internal/xds/xdsclient/tests/resource_update_test.go index 87d5653fa006..59513304ab53 100644 --- a/internal/xds/xdsclient/tests/resource_update_test.go +++ b/internal/xds/xdsclient/tests/resource_update_test.go @@ -875,7 +875,7 @@ func (s) TestHandleClusterResponseFromManagementServer(t *testing.T) { // server at that point, hence we do it here before verifying the // received update. if test.wantErr == "" { - serverCfg, err := bootstrap.ServerConfigForTesting(bootstrap.ServerConfigTestingOptions{URI: fmt.Sprintf("passthrough:///%s", mgmtServer.Address)}) + serverCfg, err := bootstrap.ServerConfigForTesting(bootstrap.ServerConfigTestingOptions{URI: fmt.Sprintf("passthrough:///%s", mgmtServer.Address), ServerFeatures: []string{"trusted_xds_server"}}) if err != nil { t.Fatalf("Failed to create server config for testing: %v", err) } From f04a488e4a555f0820404aec1c095d19b9c5e7b3 Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Mon, 29 Dec 2025 09:21:57 +0000 Subject: [PATCH 4/9] update tests --- internal/xds/balancer/clusterimpl/tests/balancer_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/xds/balancer/clusterimpl/tests/balancer_test.go b/internal/xds/balancer/clusterimpl/tests/balancer_test.go index f137d06fc8ee..b09c5abb741e 100644 --- a/internal/xds/balancer/clusterimpl/tests/balancer_test.go +++ b/internal/xds/balancer/clusterimpl/tests/balancer_test.go @@ -1335,7 +1335,7 @@ func setupManagementServerAndResolver(t *testing.T) (*e2e.ManagementServer, reso // configureXDSResources configures the management server with a route that // enables auto_host_rewrite and an endpoint with the specified hostname. -func configureXDSResources(ctx context.Context, t *testing.T, mgmtServer *e2e.ManagementServer, nodeID string, serverAddr string, endpointHostname string) { +func configureXDSResources(ctx context.Context, t *testing.T, mgmtServer *e2e.ManagementServer, nodeID string, serverAddr string, endpointHostname string, secLevel e2e.SecurityLevel) { t.Helper() const ( @@ -1350,7 +1350,7 @@ func configureXDSResources(ctx context.Context, t *testing.T, mgmtServer *e2e.Ma NodeID: nodeID, Host: "localhost", Port: testutils.ParsePort(t, serverAddr), - SecLevel: e2e.SecurityLevelMTLS, + SecLevel: secLevel, }) // Set the endpoint hostname for authority rewriting. @@ -1391,7 +1391,7 @@ func (s) TestAuthorityOverriding(t *testing.T) { const xdsAuthorityOverride = "rewritten.example.com" ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel() - configureXDSResources(ctx, t, mgmtServer, nodeID, server.Address, xdsAuthorityOverride) + configureXDSResources(ctx, t, mgmtServer, nodeID, server.Address, xdsAuthorityOverride, e2e.SecurityLevelNone) // Create a ClientConn and make a successful RPC. cc, err := grpc.NewClient("xds:///my-test-xds-service", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithResolvers(resolverBuilder)) @@ -1483,7 +1483,7 @@ func (s) TestAuthorityOverridingWithTLS(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) defer cancel() - configureXDSResources(ctx, t, mgmtServer, nodeID, f.Address, test.xdsAuthorityOverride) + configureXDSResources(ctx, t, mgmtServer, nodeID, f.Address, test.xdsAuthorityOverride, e2e.SecurityLevelMTLS) // Create ClientConn with TLS cc, err := grpc.NewClient("xds:///my-test-xds-service", grpc.WithTransportCredentials(clientCreds), grpc.WithResolvers(resolverBuilder)) From cc621ca14846c2f5f2454933eb4a50078317c0b8 Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Mon, 29 Dec 2025 09:54:58 +0000 Subject: [PATCH 5/9] resolving nits --- internal/xds/balancer/clusterimpl/clusterimpl.go | 2 +- internal/xds/xdsclient/xdsresource/unmarshal_eds.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/xds/balancer/clusterimpl/clusterimpl.go b/internal/xds/balancer/clusterimpl/clusterimpl.go index c45c39859a0c..2b77de6cc9e4 100644 --- a/internal/xds/balancer/clusterimpl/clusterimpl.go +++ b/internal/xds/balancer/clusterimpl/clusterimpl.go @@ -446,7 +446,7 @@ func (b *clusterImplBalancer) NewSubConn(addrs []resolver.Address, opts balancer var sc balancer.SubConn scw := &scWrapper{} if len(addrs) > 0 { - scw.hostname = xdsresource.HostnameFromAddress(addrs[0]) + scw.hostname = xdsresource.Hostname(addrs[0]) } oldListener := opts.StateListener opts.StateListener = func(state balancer.SubConnState) { diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_eds.go b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go index cee5ca98b5d2..ae8d1a692e4e 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_eds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go @@ -51,9 +51,9 @@ func setHostname(endpoint resolver.Endpoint, hostname string) resolver.Endpoint return endpoint } -// HostnameFromAddress returns the hostname BalancerAttributes of Address. +// Hostname returns the hostname BalancerAttributes of Address. // If this attribute is not set, it returns the empty string. -func HostnameFromAddress(addr resolver.Address) string { +func Hostname(addr resolver.Address) string { hostname, _ := addr.BalancerAttributes.Value(hostnameKeyType{}).(string) return hostname } From bbfcadcc137e5d47380e481b2fd0d502142230f9 Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Fri, 2 Jan 2026 08:53:43 +0000 Subject: [PATCH 6/9] resolving comments --- internal/transport/transport.go | 11 ++++++++--- internal/xds/balancer/clusterimpl/clusterimpl.go | 1 - internal/xds/balancer/clusterimpl/picker.go | 14 +++++++------- internal/xds/resolver/serviceconfig.go | 4 +++- internal/xds/resolver/xds_resolver_test.go | 2 +- .../xds/xdsclient/xdsresource/unmarshal_eds.go | 4 ++-- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/internal/transport/transport.go b/internal/transport/transport.go index 6daf1e002dc2..143eddfd7414 100644 --- a/internal/transport/transport.go +++ b/internal/transport/transport.go @@ -574,9 +574,14 @@ type CallHdr struct { DoneFunc func() // called when the stream is finished - // Authority is used to explicitly override the `:authority` header. If set, - // this value takes precedence over the Host field and will be used as the - // value for the `:authority` header. + // Authority is used to explicitly override the `:authority` header. + // + // This value comes from one of two sources: + // 1. The `CallAuthority` call option, if specified by the user. + // 2. An override provided by the LB picker (e.g. xDS authority rewriting). + // + // The `CallAuthority` call option always takes precedence over the LB + // picker override. Authority string } diff --git a/internal/xds/balancer/clusterimpl/clusterimpl.go b/internal/xds/balancer/clusterimpl/clusterimpl.go index 2b77de6cc9e4..a7ac3032b922 100644 --- a/internal/xds/balancer/clusterimpl/clusterimpl.go +++ b/internal/xds/balancer/clusterimpl/clusterimpl.go @@ -421,7 +421,6 @@ type scWrapper struct { // locality needs to be atomic because it can be updated while being read by // the picker. locality atomic.Pointer[clients.Locality] - hostname string } diff --git a/internal/xds/balancer/clusterimpl/picker.go b/internal/xds/balancer/clusterimpl/picker.go index c60dda6b5a42..75c268913509 100644 --- a/internal/xds/balancer/clusterimpl/picker.go +++ b/internal/xds/balancer/clusterimpl/picker.go @@ -147,7 +147,7 @@ func (d *picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) { // be used. lID = scw.localityID() - if scw.hostname != "" && autoHostRewrite(info.Ctx) { + if scw.hostname != "" && autoHostRewriteEnabled(info.Ctx) { if pr.Metadata == nil { pr.Metadata = metadata.Pairs(":authority", scw.hostname) } else { @@ -209,19 +209,19 @@ func (d *picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) { type autoHostRewriteKey struct{} // autoHostRewrite retrieves the autoHostRewrite value from the provided context. -func autoHostRewrite(ctx context.Context) bool { +func autoHostRewriteEnabled(ctx context.Context) bool { v, _ := ctx.Value(autoHostRewriteKey{}).(bool) return v } // AutoHostRewriteForTesting returns the value of autoHostRewrite field; // to be used for testing only. -func AutoHostRewriteForTesting(ctx context.Context) bool { - return autoHostRewrite(ctx) +func AutoHostRewriteEnabledForTesting(ctx context.Context) bool { + return autoHostRewriteEnabled(ctx) } -// SetAutoHostRewrite adds the autoHostRewrite value to the context for +// EnableAutoHostRewrite adds the autoHostRewrite value to the context for // the xds_cluster_impl LB policy to pick. -func SetAutoHostRewrite(ctx context.Context, autohostRewrite bool) context.Context { - return context.WithValue(ctx, autoHostRewriteKey{}, autohostRewrite) +func EnableAutoHostRewrite(ctx context.Context) context.Context { + return context.WithValue(ctx, autoHostRewriteKey{}, true) } diff --git a/internal/xds/resolver/serviceconfig.go b/internal/xds/resolver/serviceconfig.go index e04163666dcb..40a423f1f1e2 100644 --- a/internal/xds/resolver/serviceconfig.go +++ b/internal/xds/resolver/serviceconfig.go @@ -199,7 +199,9 @@ func (cs *configSelector) SelectConfig(rpcInfo iresolver.RPCInfo) (*iresolver.RP lbCtx := clustermanager.SetPickedCluster(rpcInfo.Context, cluster.name) lbCtx = iringhash.SetXDSRequestHash(lbCtx, cs.generateHash(rpcInfo, rt.hashPolicies)) - lbCtx = clusterimpl.SetAutoHostRewrite(lbCtx, rt.autoHostRewrite) + if rt.autoHostRewrite { + lbCtx = clusterimpl.EnableAutoHostRewrite(lbCtx) + } config := &iresolver.RPCConfig{ // Communicate to the LB policy the chosen cluster and request hash, if Ring Hash LB policy. diff --git a/internal/xds/resolver/xds_resolver_test.go b/internal/xds/resolver/xds_resolver_test.go index 16d6fd76b1f9..999413d16569 100644 --- a/internal/xds/resolver/xds_resolver_test.go +++ b/internal/xds/resolver/xds_resolver_test.go @@ -1443,7 +1443,7 @@ func (s) TestResolver_AutoHostRewrite(t *testing.T) { t.Fatalf("cs.SelectConfig(): %v", err) } - gotAutoHostRewrite := clusterimpl.AutoHostRewriteForTesting(res.Context) + gotAutoHostRewrite := clusterimpl.AutoHostRewriteEnabledForTesting(res.Context) if gotAutoHostRewrite != tt.wantAutoHostRewrite { t.Fatalf("Got autoHostRewrite: %v, want: %v", gotAutoHostRewrite, tt.wantAutoHostRewrite) } diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_eds.go b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go index ae8d1a692e4e..becd61de845b 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_eds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go @@ -51,8 +51,8 @@ func setHostname(endpoint resolver.Endpoint, hostname string) resolver.Endpoint return endpoint } -// Hostname returns the hostname BalancerAttributes of Address. -// If this attribute is not set, it returns the empty string. +// Hostname returns the hostname from the BalancerAttributes of the given +// Address. If this attribute is not set, it returns the empty string. func Hostname(addr resolver.Address) string { hostname, _ := addr.BalancerAttributes.Value(hostnameKeyType{}).(string) return hostname From a9d10ab9021af41a491598f0c55e850ef0fa9a25 Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Fri, 2 Jan 2026 08:59:07 +0000 Subject: [PATCH 7/9] resolving comments --- internal/xds/balancer/clusterimpl/picker.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/xds/balancer/clusterimpl/picker.go b/internal/xds/balancer/clusterimpl/picker.go index 75c268913509..b73b108e9011 100644 --- a/internal/xds/balancer/clusterimpl/picker.go +++ b/internal/xds/balancer/clusterimpl/picker.go @@ -208,13 +208,13 @@ func (d *picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) { // route's autoHostRewrite in the RPC context. type autoHostRewriteKey struct{} -// autoHostRewrite retrieves the autoHostRewrite value from the provided context. +// autoHostRewriteEnabled retrieves the autoHostRewrite value from the provided context. func autoHostRewriteEnabled(ctx context.Context) bool { v, _ := ctx.Value(autoHostRewriteKey{}).(bool) return v } -// AutoHostRewriteForTesting returns the value of autoHostRewrite field; +// AutoHostRewriteEnabledForTesting returns the value of autoHostRewrite field; // to be used for testing only. func AutoHostRewriteEnabledForTesting(ctx context.Context) bool { return autoHostRewriteEnabled(ctx) From 1da99666159175cefd9dd4807f0d3097af1caab7 Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Sat, 3 Jan 2026 19:33:09 +0000 Subject: [PATCH 8/9] update test --- .../balancer/clusterimpl/tests/balancer_test.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/internal/xds/balancer/clusterimpl/tests/balancer_test.go b/internal/xds/balancer/clusterimpl/tests/balancer_test.go index b09c5abb741e..9dc16b323045 100644 --- a/internal/xds/balancer/clusterimpl/tests/balancer_test.go +++ b/internal/xds/balancer/clusterimpl/tests/balancer_test.go @@ -39,6 +39,7 @@ import ( "google.golang.org/grpc/balancer/pickfirst" "google.golang.org/grpc/codes" "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal" "google.golang.org/grpc/internal/balancer/stub" @@ -1493,7 +1494,8 @@ func (s) TestAuthorityOverridingWithTLS(t *testing.T) { defer cc.Close() client := testgrpc.NewTestServiceClient(cc) - _, err = client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)) + peer := &peer.Peer{} + _, err = client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true), grpc.Peer(peer)) if test.expectSuccess { if err != nil { @@ -1504,6 +1506,17 @@ func (s) TestAuthorityOverridingWithTLS(t *testing.T) { if gotAuth != test.xdsAuthorityOverride { t.Errorf("invalid authority got: %q, want: %q", gotAuth, test.xdsAuthorityOverride) } + ai, ok := peer.AuthInfo.(credentials.TLSInfo) + if !ok { + t.Fatalf("AuthInfo type is %T, want %T", peer.AuthInfo, credentials.TLSInfo{}) + } + if len(ai.State.PeerCertificates) != 1 { + t.Fatalf("Number of peer certificates is %d, want 1", len(ai.State.PeerCertificates)) + } + cert := ai.State.PeerCertificates[0] + if cert.Subject.CommonName != "test-server1" { + t.Fatalf("Common name in peer certificate is %s, want test-server1", cert.Subject.CommonName) + } case <-ctx.Done(): t.Fatalf("Timeout waiting for successful RPC after authority rewriting.") } From 0856922529644a47d3a5fafa7b3d9750be7402fc Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Mon, 5 Jan 2026 06:20:34 +0000 Subject: [PATCH 9/9] resolving comments --- balancer/ringhash/ringhash_e2e_test.go | 3 - .../cdsbalancer/cdsbalancer_security_test.go | 3 - .../balancer/cdsbalancer/cdsbalancer_test.go | 3 - .../cdsbalancer/e2e_test/balancer_test.go | 3 - .../clusterimpl/tests/balancer_test.go | 92 ++++--------------- internal/xds/httpfilter/fault/fault_test.go | 6 -- internal/xds/resolver/helpers_test.go | 3 - .../xds/resolver/xds_http_filters_test.go | 6 -- internal/xds/resolver/xds_resolver_test.go | 11 --- test/xds/xds_client_ack_nack_test.go | 3 - .../xds_client_certificate_providers_test.go | 3 - test/xds/xds_client_federation_test.go | 6 -- ...ds_client_ignore_resource_deletion_test.go | 3 - test/xds/xds_security_config_nack_test.go | 3 - test/xds/xds_server_integration_test.go | 3 - 15 files changed, 16 insertions(+), 135 deletions(-) diff --git a/balancer/ringhash/ringhash_e2e_test.go b/balancer/ringhash/ringhash_e2e_test.go index 98c5b6ff54b6..b901e971344e 100644 --- a/balancer/ringhash/ringhash_e2e_test.go +++ b/balancer/ringhash/ringhash_e2e_test.go @@ -299,9 +299,6 @@ func setupManagementServerAndResolver(t *testing.T) (*e2e.ManagementServer, stri bc := e2e.DefaultBootstrapContents(t, nodeID, xdsServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } r, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) diff --git a/internal/xds/balancer/cdsbalancer/cdsbalancer_security_test.go b/internal/xds/balancer/cdsbalancer/cdsbalancer_security_test.go index f26571fd8cfa..5ee152208eba 100644 --- a/internal/xds/balancer/cdsbalancer/cdsbalancer_security_test.go +++ b/internal/xds/balancer/cdsbalancer/cdsbalancer_security_test.go @@ -68,9 +68,6 @@ import ( func setupForSecurityTests(t *testing.T, bootstrapContents []byte, clientCreds, serverCreds credentials.TransportCredentials) (*grpc.ClientConn, string) { t.Helper() - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } r, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) diff --git a/internal/xds/balancer/cdsbalancer/cdsbalancer_test.go b/internal/xds/balancer/cdsbalancer/cdsbalancer_test.go index 00041bbd5a72..c2a739995f46 100644 --- a/internal/xds/balancer/cdsbalancer/cdsbalancer_test.go +++ b/internal/xds/balancer/cdsbalancer/cdsbalancer_test.go @@ -247,9 +247,6 @@ func setupWithManagementServer(t *testing.T, lis net.Listener, onStreamRequest f nodeID := uuid.New().String() bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } r, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) diff --git a/internal/xds/balancer/cdsbalancer/e2e_test/balancer_test.go b/internal/xds/balancer/cdsbalancer/e2e_test/balancer_test.go index 5db316dc2e9e..51bdd538131f 100644 --- a/internal/xds/balancer/cdsbalancer/e2e_test/balancer_test.go +++ b/internal/xds/balancer/cdsbalancer/e2e_test/balancer_test.go @@ -74,9 +74,6 @@ import ( func setupAndDial(t *testing.T, bootstrapContents []byte) (*grpc.ClientConn, func()) { t.Helper() // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } r, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents) if err != nil { t.Fatalf("xDS resolver creation failed: %v", err) diff --git a/internal/xds/balancer/clusterimpl/tests/balancer_test.go b/internal/xds/balancer/clusterimpl/tests/balancer_test.go index 9dc16b323045..f0418aba3030 100644 --- a/internal/xds/balancer/clusterimpl/tests/balancer_test.go +++ b/internal/xds/balancer/clusterimpl/tests/balancer_test.go @@ -39,7 +39,6 @@ import ( "google.golang.org/grpc/balancer/pickfirst" "google.golang.org/grpc/codes" "google.golang.org/grpc/connectivity" - "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal" "google.golang.org/grpc/internal/balancer/stub" @@ -102,9 +101,6 @@ func (s) TestConfigUpdateWithSameLoadReportingServerConfig(t *testing.T) { bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -210,9 +206,6 @@ func (s) TestLoadReportingPickFirstMultiLocality(t *testing.T) { bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -383,9 +376,6 @@ func (s) TestCircuitBreaking(t *testing.T) { bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -579,9 +569,6 @@ func (s) TestDropByCategory(t *testing.T) { bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -721,9 +708,6 @@ func (s) TestCircuitBreakingLogicalDNS(t *testing.T) { bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -839,9 +823,6 @@ func (s) TestLRSLogicalDNS(t *testing.T) { bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -930,9 +911,6 @@ func (s) TestReResolutionAfterTransientFailure(t *testing.T) { bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -1049,9 +1027,6 @@ func (s) TestUpdateLRSServerToNil(t *testing.T) { bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -1135,9 +1110,6 @@ func (s) TestChildPolicyChangeOnConfigUpdate(t *testing.T) { bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -1257,9 +1229,6 @@ func (s) TestFailedToParseChildPolicyConfig(t *testing.T) { bc := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -1323,9 +1292,6 @@ func setupManagementServerAndResolver(t *testing.T) (*e2e.ManagementServer, reso contents := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(contents) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -1375,12 +1341,12 @@ func (s) TestAuthorityOverriding(t *testing.T) { mgmtServer, resolverBuilder, nodeID := setupManagementServerAndResolver(t) // Start a server backend exposing the test service. - authorityCh := make(chan string, 1) + var gotAuthority string f := &stubserver.StubServer{ EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) { if md, ok := metadata.FromIncomingContext(ctx); ok { if authVals := md.Get(":authority"); len(authVals) > 0 { - authorityCh <- authVals[0] + gotAuthority = authVals[0] } } return &testpb.Empty{}, nil @@ -1406,13 +1372,8 @@ func (s) TestAuthorityOverriding(t *testing.T) { t.Fatalf("client.EmptyCall() failed: %v", err) } - select { - case gotAuth := <-authorityCh: - if gotAuth != xdsAuthorityOverride { - t.Errorf("invalid authority got: %q, want: %q", gotAuth, xdsAuthorityOverride) - } - case <-ctx.Done(): - t.Fatalf("Timeout waiting for successful RPC after authority rewriting.") + if gotAuthority != xdsAuthorityOverride { + t.Errorf("invalid authority got: %q, want: %q", gotAuthority, xdsAuthorityOverride) } // The authority specified via the `CallAuthority` CallOption takes the @@ -1422,13 +1383,8 @@ func (s) TestAuthorityOverriding(t *testing.T) { t.Fatalf("client.EmptyCall() failed: %v", err) } - select { - case got := <-authorityCh: - if got != userAuthorityOverride { - t.Errorf("Server received authority %q, want %q (user override)", got, userAuthorityOverride) - } - case <-ctx.Done(): - t.Fatalf("Timeout waiting for successful RPC.") + if gotAuthority != userAuthorityOverride { + t.Errorf("Server received authority %q, want %q (user override)", gotAuthority, userAuthorityOverride) } } @@ -1442,17 +1398,17 @@ func (s) TestAuthorityOverridingWithTLS(t *testing.T) { tests := []struct { name string xdsAuthorityOverride string - expectSuccess bool + wantSuccess bool }{ { name: "Valid_Authority_Rewrite", xdsAuthorityOverride: "x.test.example.com", - expectSuccess: true, + wantSuccess: true, }, { name: "Authority_Rewrite_Mismatch", xdsAuthorityOverride: "xyz.exmaple.com", - expectSuccess: false, + wantSuccess: false, }, } for _, test := range tests { @@ -1463,12 +1419,12 @@ func (s) TestAuthorityOverridingWithTLS(t *testing.T) { serverCreds := testutils.CreateServerTLSCredentials(t, tls.RequireAndVerifyClientCert) // Start a server backend exposing the test service. - authorityCh := make(chan string, 1) + var gotAuthority string f := &stubserver.StubServer{ EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) { if md, ok := metadata.FromIncomingContext(ctx); ok { if authVals := md.Get(":authority"); len(authVals) > 0 { - authorityCh <- authVals[0] + gotAuthority = authVals[0] } } return &testpb.Empty{}, nil @@ -1497,32 +1453,16 @@ func (s) TestAuthorityOverridingWithTLS(t *testing.T) { peer := &peer.Peer{} _, err = client.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true), grpc.Peer(peer)) - if test.expectSuccess { + if test.wantSuccess { if err != nil { t.Fatalf("RPC failed unexpectedly: %v", err) } - select { - case gotAuth := <-authorityCh: - if gotAuth != test.xdsAuthorityOverride { - t.Errorf("invalid authority got: %q, want: %q", gotAuth, test.xdsAuthorityOverride) - } - ai, ok := peer.AuthInfo.(credentials.TLSInfo) - if !ok { - t.Fatalf("AuthInfo type is %T, want %T", peer.AuthInfo, credentials.TLSInfo{}) - } - if len(ai.State.PeerCertificates) != 1 { - t.Fatalf("Number of peer certificates is %d, want 1", len(ai.State.PeerCertificates)) - } - cert := ai.State.PeerCertificates[0] - if cert.Subject.CommonName != "test-server1" { - t.Fatalf("Common name in peer certificate is %s, want test-server1", cert.Subject.CommonName) - } - case <-ctx.Done(): - t.Fatalf("Timeout waiting for successful RPC after authority rewriting.") + if gotAuthority != test.xdsAuthorityOverride { + t.Errorf("invalid authority got: %q, want: %q", gotAuthority, test.xdsAuthorityOverride) } } else { - if err == nil || !strings.Contains(err.Error(), "invalid authority") { - t.Fatal("RPC succeeded unexpectedly; expected TLS failure due to authority mismatch") + if status.Code(err) != codes.Unavailable { + t.Fatalf("Expected TLS failure due to authority mismatch, got: %q want: %q", codes.Unavailable, status.Code(err)) } } }) diff --git a/internal/xds/httpfilter/fault/fault_test.go b/internal/xds/httpfilter/fault/fault_test.go index 2612094baa5a..1f77ad3943aa 100644 --- a/internal/xds/httpfilter/fault/fault_test.go +++ b/internal/xds/httpfilter/fault/fault_test.go @@ -461,9 +461,6 @@ func (s) TestFaultInjection_Unary(t *testing.T) { fs, nodeID, port, bc := clientSetup(t) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -551,9 +548,6 @@ func (s) TestFaultInjection_Unary(t *testing.T) { func (s) TestFaultInjection_MaxActiveFaults(t *testing.T) { fs, nodeID, port, bc := clientSetup(t) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) diff --git a/internal/xds/resolver/helpers_test.go b/internal/xds/resolver/helpers_test.go index 174b03883445..2f0049188460 100644 --- a/internal/xds/resolver/helpers_test.go +++ b/internal/xds/resolver/helpers_test.go @@ -103,9 +103,6 @@ func buildResolverForTarget(t *testing.T, target resolver.Target, bootstrapConte var builder resolver.Builder if bootstrapContents != nil { // Create an xDS resolver with the provided bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } var err error builder, err = internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents) if err != nil { diff --git a/internal/xds/resolver/xds_http_filters_test.go b/internal/xds/resolver/xds_http_filters_test.go index 9d2c5acf0b43..55e2060256b5 100644 --- a/internal/xds/resolver/xds_http_filters_test.go +++ b/internal/xds/resolver/xds_http_filters_test.go @@ -268,9 +268,6 @@ func (s) TestXDSResolverHTTPFilters_AllOverrides(t *testing.T) { // management server. nodeID := uuid.New().String() bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -526,9 +523,6 @@ func (s) TestXDSResolverHTTPFilters_NewStreamError(t *testing.T) { // management server. nodeID := uuid.New().String() bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, mgmtServer.Address) - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) diff --git a/internal/xds/resolver/xds_resolver_test.go b/internal/xds/resolver/xds_resolver_test.go index 999413d16569..ebe225b3b822 100644 --- a/internal/xds/resolver/xds_resolver_test.go +++ b/internal/xds/resolver/xds_resolver_test.go @@ -95,9 +95,6 @@ func (s) TestResolverBuilder_AuthorityNotDefinedInBootstrap(t *testing.T) { contents := e2e.DefaultBootstrapContents(t, "node-id", "dummy-management-server") // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(contents) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -310,10 +307,6 @@ func (s) TestNoMatchingVirtualHost(t *testing.T) { target := resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)} // Create an xDS resolver with the provided bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } - builder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -383,10 +376,6 @@ func (s) TestResolverBadServiceUpdate_NACKedWithoutCache(t *testing.T) { target := resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)} // Create an xDS resolver with the provided bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } - builder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) diff --git a/test/xds/xds_client_ack_nack_test.go b/test/xds/xds_client_ack_nack_test.go index 4ff6272e7b7a..05f5a1bd59a3 100644 --- a/test/xds/xds_client_ack_nack_test.go +++ b/test/xds/xds_client_ack_nack_test.go @@ -131,9 +131,6 @@ func (s) TestClientResourceVersionAfterStreamRestart(t *testing.T) { bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, managementServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) diff --git a/test/xds/xds_client_certificate_providers_test.go b/test/xds/xds_client_certificate_providers_test.go index 03bcd603c812..b7b2fc4610df 100644 --- a/test/xds/xds_client_certificate_providers_test.go +++ b/test/xds/xds_client_certificate_providers_test.go @@ -129,9 +129,6 @@ func (s) TestClientSideXDS_WithNoCertificateProvidersInBootstrap_Failure(t *test } // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolverBuilder, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bc) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) diff --git a/test/xds/xds_client_federation_test.go b/test/xds/xds_client_federation_test.go index df4a7a1383bb..815b520f4710 100644 --- a/test/xds/xds_client_federation_test.go +++ b/test/xds/xds_client_federation_test.go @@ -87,9 +87,6 @@ func (s) TestClientSideFederation(t *testing.T) { t.Fatalf("Failed to create bootstrap file: %v", err) } - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) @@ -183,9 +180,6 @@ func (s) TestClientSideFederationWithOnlyXDSTPStyleLDS(t *testing.T) { t.Fatalf("Failed to create bootstrap file: %v", err) } - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } resolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) diff --git a/test/xds/xds_client_ignore_resource_deletion_test.go b/test/xds/xds_client_ignore_resource_deletion_test.go index 4459ed299844..dd55adb1865d 100644 --- a/test/xds/xds_client_ignore_resource_deletion_test.go +++ b/test/xds/xds_client_ignore_resource_deletion_test.go @@ -301,9 +301,6 @@ func generateBootstrapContents(t *testing.T, serverURI string, ignoreResourceDel // as parameter. func xdsResolverBuilder(t *testing.T, bs []byte) resolver.Builder { t.Helper() - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } xdsR, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bs) if err != nil { t.Fatalf("Creating xDS resolver for testing failed for config %q: %v", string(bs), err) diff --git a/test/xds/xds_security_config_nack_test.go b/test/xds/xds_security_config_nack_test.go index f1e512a2261c..0efc080251b7 100644 --- a/test/xds/xds_security_config_nack_test.go +++ b/test/xds/xds_security_config_nack_test.go @@ -329,9 +329,6 @@ func (s) TestUnmarshalCluster_WithUpdateValidatorFunc(t *testing.T) { bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, managementServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err) diff --git a/test/xds/xds_server_integration_test.go b/test/xds/xds_server_integration_test.go index 1dcfcc1eee83..ff56c9ea97e1 100644 --- a/test/xds/xds_server_integration_test.go +++ b/test/xds/xds_server_integration_test.go @@ -327,9 +327,6 @@ func (s) TestServerSideXDS_SecurityConfigChange(t *testing.T) { bootstrapContents := e2e.DefaultBootstrapContents(t, nodeID, managementServer.Address) // Create an xDS resolver with the above bootstrap configuration. - if internal.NewXDSResolverWithConfigForTesting == nil { - t.Fatalf("internal.NewXDSResolverWithConfigForTesting is nil") - } xdsResolver, err := internal.NewXDSResolverWithConfigForTesting.(func([]byte) (resolver.Builder, error))(bootstrapContents) if err != nil { t.Fatalf("Failed to create xDS resolver for testing: %v", err)