xds bootstrap: support insecure and make Creds required (#3881)

diff --git a/xds/internal/balancer/edsbalancer/xds_client_wrapper.go b/xds/internal/balancer/edsbalancer/xds_client_wrapper.go
index 06b4584..dd66a41 100644
--- a/xds/internal/balancer/edsbalancer/xds_client_wrapper.go
+++ b/xds/internal/balancer/edsbalancer/xds_client_wrapper.go
@@ -141,14 +141,6 @@
 		return false
 	}
 
-	if clientConfig.Creds == nil {
-		// TODO: Once we start supporting a mechanism to register credential
-		// types, a failure to find the credential type mentioned in the
-		// bootstrap file should result in a failure, and not in using
-		// credentials from the parent channel (passed through the
-		// resolver.BuildOptions).
-		clientConfig.Creds = c.defaultDialCreds(clientConfig.BalancerName)
-	}
 	var dopts []grpc.DialOption
 	if dialer := c.bbo.Dialer; dialer != nil {
 		dopts = []grpc.DialOption{grpc.WithContextDialer(dialer)}
@@ -281,28 +273,6 @@
 	}
 }
 
-// defaultDialCreds builds a DialOption containing the credentials to be used
-// while talking to the xDS server (this is done only if the xds bootstrap
-// process does not return any credentials to use). If the parent channel
-// contains DialCreds, we use it as is. If it contains a CredsBundle, we use
-// just the transport credentials from the bundle. If we don't find any
-// credentials on the parent channel, we resort to using an insecure channel.
-func (c *xdsclientWrapper) defaultDialCreds(balancerName string) grpc.DialOption {
-	switch {
-	case c.bbo.DialCreds != nil:
-		if err := c.bbo.DialCreds.OverrideServerName(balancerName); err != nil {
-			c.logger.Warningf("xds: failed to override server name in credentials: %v, using Insecure", err)
-			return grpc.WithInsecure()
-		}
-		return grpc.WithTransportCredentials(c.bbo.DialCreds)
-	case c.bbo.CredsBundle != nil:
-		return grpc.WithTransportCredentials(c.bbo.CredsBundle.TransportCredentials())
-	default:
-		c.logger.Warningf("xds: no credentials available, using Insecure")
-		return grpc.WithInsecure()
-	}
-}
-
 // equalStringPointers returns true if
 // - a and b are both nil OR
 // - *a == *b (and a and b are both non-nil)
diff --git a/xds/internal/client/bootstrap/bootstrap.go b/xds/internal/client/bootstrap/bootstrap.go
index b2805bf..e3f2ce5 100644
--- a/xds/internal/client/bootstrap/bootstrap.go
+++ b/xds/internal/client/bootstrap/bootstrap.go
@@ -47,7 +47,8 @@
 	serverFeaturesV3 = "xds_v3"
 
 	// Type name for Google default credentials.
-	googleDefaultCreds              = "google_default"
+	credsGoogleDefault              = "google_default"
+	credsInsecure                   = "insecure"
 	gRPCUserAgentName               = "gRPC Go"
 	clientFeatureNoOverprovisioning = "envoy.lb.does_not_support_overprovisioning"
 )
@@ -161,9 +162,12 @@
 			xs := servers[0]
 			config.BalancerName = xs.ServerURI
 			for _, cc := range xs.ChannelCreds {
-				if cc.Type == googleDefaultCreds {
+				// We stop at the first credential type that we support.
+				if cc.Type == credsGoogleDefault {
 					config.Creds = grpc.WithCredentialsBundle(google.NewDefaultCredentials())
-					// We stop at the first credential type that we support.
+					break
+				} else if cc.Type == credsInsecure {
+					config.Creds = grpc.WithInsecure()
 					break
 				}
 			}
@@ -185,7 +189,10 @@
 	}
 
 	if config.BalancerName == "" {
-		return nil, fmt.Errorf("xds: Required field %q not found in bootstrap", "xds_servers.server_uri")
+		return nil, fmt.Errorf("xds: Required field %q not found in bootstrap %s", "xds_servers.server_uri", jsonData["xds_servers"])
+	}
+	if config.Creds == nil {
+		return nil, fmt.Errorf("xds: Required field %q doesn't contain valid value in bootstrap %s", "xds_servers.channel_creds", jsonData["xds_servers"])
 	}
 
 	// We end up using v3 transport protocol version only if the following
diff --git a/xds/internal/client/bootstrap/bootstrap_test.go b/xds/internal/client/bootstrap/bootstrap_test.go
index 18c28db..a7734f0 100644
--- a/xds/internal/client/bootstrap/bootstrap_test.go
+++ b/xds/internal/client/bootstrap/bootstrap_test.go
@@ -38,7 +38,10 @@
 		"emptyNodeProto": `
 		{
 			"xds_servers" : [{
-				"server_uri": "trafficdirector.googleapis.com:443"
+				"server_uri": "trafficdirector.googleapis.com:443",
+				"channel_creds": [
+					{ "type": "insecure" }
+				]
 			}]
 		}`,
 		"unknownTopLevelFieldInFile": `
@@ -52,7 +55,7 @@
 			"xds_servers" : [{
 				"server_uri": "trafficdirector.googleapis.com:443",
 				"channel_creds": [
-					{ "type": "not-google-default" }
+					{ "type": "insecure" }
 				]
 			}],
 			"unknownField": "foobar"
@@ -67,7 +70,10 @@
 			    }
 			},
 			"xds_servers" : [{
-				"server_uri": "trafficdirector.googleapis.com:443"
+				"server_uri": "trafficdirector.googleapis.com:443",
+				"channel_creds": [
+					{ "type": "insecure" }
+				]
 			}]
 		}`,
 		"unknownFieldInXdsServer": `
@@ -81,38 +87,11 @@
 			"xds_servers" : [{
 				"server_uri": "trafficdirector.googleapis.com:443",
 				"channel_creds": [
-					{ "type": "not-google-default" }
+					{ "type": "insecure" }
 				],
 				"unknownField": "foobar"
 			}]
 		}`,
-		"emptyChannelCreds": `
-		{
-			"node": {
-				"id": "ENVOY_NODE_ID",
-				"metadata": {
-				    "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector"
-			    }
-			},
-			"xds_servers" : [{
-				"server_uri": "trafficdirector.googleapis.com:443"
-			}]
-		}`,
-		"nonGoogleDefaultCreds": `
-		{
-			"node": {
-				"id": "ENVOY_NODE_ID",
-				"metadata": {
-				    "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector"
-			    }
-			},
-			"xds_servers" : [{
-				"server_uri": "trafficdirector.googleapis.com:443",
-				"channel_creds": [
-					{ "type": "not-google-default" }
-				]
-			}]
-		}`,
 		"multipleChannelCreds": `
 		{
 			"node": {
@@ -222,7 +201,7 @@
 	}
 	nilCredsConfigV2 = &Config{
 		BalancerName: "trafficdirector.googleapis.com:443",
-		Creds:        nil,
+		Creds:        grpc.WithInsecure(),
 		NodeProto:    v2NodeProto,
 	}
 	nonNilCredsConfigV2 = &Config{
@@ -290,6 +269,33 @@
 			    }
 			}
 		}`,
+		"emptyChannelCreds": `
+		{
+			"node": {
+				"id": "ENVOY_NODE_ID",
+				"metadata": {
+				    "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector"
+			    }
+			},
+			"xds_servers" : [{
+				"server_uri": "trafficdirector.googleapis.com:443"
+			}]
+		}`,
+		"nonGoogleDefaultCreds": `
+		{
+			"node": {
+				"id": "ENVOY_NODE_ID",
+				"metadata": {
+				    "TRAFFICDIRECTOR_GRPC_HOSTNAME": "trafficdirector"
+			    }
+			},
+			"xds_servers" : [{
+				"server_uri": "trafficdirector.googleapis.com:443",
+				"channel_creds": [
+					{ "type": "not-google-default" }
+				]
+			}]
+		}`,
 	}
 	cancel := setupBootstrapOverride(bootstrapFileMap)
 	defer cancel()
@@ -331,6 +337,7 @@
 		{
 			"emptyNodeProto", &Config{
 				BalancerName: "trafficdirector.googleapis.com:443",
+				Creds:        grpc.WithInsecure(),
 				NodeProto: &v2corepb.Node{
 					BuildVersion:         gRPCVersion,
 					UserAgentName:        gRPCUserAgentName,
@@ -342,8 +349,6 @@
 		{"unknownTopLevelFieldInFile", nilCredsConfigV2},
 		{"unknownFieldInNodeProto", nilCredsConfigV2},
 		{"unknownFieldInXdsServer", nilCredsConfigV2},
-		{"emptyChannelCreds", nilCredsConfigV2},
-		{"nonGoogleDefaultCreds", nilCredsConfigV2},
 		{"multipleChannelCreds", nonNilCredsConfigV2},
 		{"goodBootstrap", nonNilCredsConfigV2},
 		{"multipleXDSServers", nonNilCredsConfigV2},
diff --git a/xds/internal/resolver/xds_resolver.go b/xds/internal/resolver/xds_resolver.go
index 02bf19c..359ee12 100644
--- a/xds/internal/resolver/xds_resolver.go
+++ b/xds/internal/resolver/xds_resolver.go
@@ -68,15 +68,6 @@
 	r.logger = prefixLogger((r))
 	r.logger.Infof("Creating resolver for target: %+v", t)
 
-	if config.Creds == nil {
-		// TODO: Once we start supporting a mechanism to register credential
-		// types, a failure to find the credential type mentioned in the
-		// bootstrap file should result in a failure, and not in using
-		// credentials from the parent channel (passed through the
-		// resolver.BuildOptions).
-		config.Creds = r.defaultDialCreds(config.BalancerName, rbo)
-	}
-
 	var dopts []grpc.DialOption
 	if rbo.Dialer != nil {
 		dopts = []grpc.DialOption{grpc.WithContextDialer(rbo.Dialer)}
@@ -100,28 +91,6 @@
 	return r, nil
 }
 
-// defaultDialCreds builds a DialOption containing the credentials to be used
-// while talking to the xDS server (this is done only if the xds bootstrap
-// process does not return any credentials to use). If the parent channel
-// contains DialCreds, we use it as is. If it contains a CredsBundle, we use
-// just the transport credentials from the bundle. If we don't find any
-// credentials on the parent channel, we resort to using an insecure channel.
-func (r *xdsResolver) defaultDialCreds(balancerName string, rbo resolver.BuildOptions) grpc.DialOption {
-	switch {
-	case rbo.DialCreds != nil:
-		if err := rbo.DialCreds.OverrideServerName(balancerName); err != nil {
-			r.logger.Errorf("Failed to override server name in credentials: %v, using Insecure", err)
-			return grpc.WithInsecure()
-		}
-		return grpc.WithTransportCredentials(rbo.DialCreds)
-	case rbo.CredsBundle != nil:
-		return grpc.WithTransportCredentials(rbo.CredsBundle.TransportCredentials())
-	default:
-		r.logger.Warningf("No credentials available, using Insecure")
-		return grpc.WithInsecure()
-	}
-}
-
 // Name helps implement the resolver.Builder interface.
 func (*xdsResolverBuilder) Scheme() string {
 	return xdsScheme
diff --git a/xds/internal/resolver/xds_resolver_test.go b/xds/internal/resolver/xds_resolver_test.go
index 9d04e3c..7eb0629 100644
--- a/xds/internal/resolver/xds_resolver_test.go
+++ b/xds/internal/resolver/xds_resolver_test.go
@@ -113,7 +113,7 @@
 		// what the want option is. We should be able to do extensive
 		// credential testing in e2e tests.
 		if (gotOpts.Config.Creds != nil) != (wantOpts.Config.Creds != nil) {
-			return nil, fmt.Errorf("got len(creds): %s, want: %s", gotOpts.Config.Creds, wantOpts.Config.Creds)
+			return nil, fmt.Errorf("got len(creds): %v, want: %v", gotOpts.Config.Creds, wantOpts.Config.Creds)
 		}
 		if len(gotOpts.DialOpts) != len(wantOpts.DialOpts) {
 			return nil, fmt.Errorf("got len(DialOpts): %v, want: %v", len(gotOpts.DialOpts), len(wantOpts.DialOpts))
@@ -159,7 +159,7 @@
 				NodeProto:    xdstestutils.EmptyNodeProtoV2,
 			},
 			xdsClientFunc: getXDSClientMakerFunc(xdsclient.Options{Config: validConfig}),
-			wantErr:       false,
+			wantErr:       true,
 		},
 		{
 			name:   "error-dialer-in-rbo",